WIP/PoC for parallel backup

Started by Asif Rehmanover 6 years ago120 messages
#1Asif Rehman
asifr.rehman@gmail.com
1 attachment(s)

Hi Hackers,

I have been looking into adding parallel backup feature in pg_basebackup.
Currently pg_basebackup sends BASE_BACKUP command for taking full backup,
server scans the PGDATA and sends the files to pg_basebackup. In general,
server takes the following steps on BASE_BACKUP command:

- do pg_start_backup
- scans PGDATA, creates and send header containing information of
tablespaces.
- sends each tablespace to pg_basebackup.
- and then do pg_stop_backup

All these steps are executed sequentially by a single process. The idea I
am working on is to separate these steps into multiple commands in
replication grammer. Add worker processes to the pg_basebackup where they
can copy the contents of PGDATA in parallel.

The command line interface syntax would be like:
pg_basebackup --jobs=WORKERS

Replication commands:

- BASE_BACKUP [PARALLEL] - returns a list of files in PGDATA
If the parallel option is there, then it will only do pg_start_backup,
scans PGDATA and sends a list of file names.

- SEND_FILES_CONTENTS (file1, file2,...) - returns the files in given list.
pg_basebackup will then send back a list of filenames in this command. This
commands will be send by each worker and that worker will be getting the
said files.

- STOP_BACKUP
when all workers finish then, pg_basebackup will send STOP_BACKUP command.

The pg_basebackup can start by sending "BASE_BACKUP PARALLEL" command and
getting a list of filenames from the server in response. It should then
divide this list as per --jobs parameter. (This division can be based on
file sizes). Each of the worker process will issue a SEND_FILES_CONTENTS
(file1, file2,...) command. In response, the server will send the files
mentioned in the list back to the requesting worker process.

Once all the files are copied, then pg_basebackup will send the STOP_BACKUP
command. Similar idea has been been discussed by Robert, on the incremental
backup thread a while ago. This is similar to that but instead of
START_BACKUP and SEND_FILE_LIST, I have combined them into BASE_BACKUP
PARALLEL.

I have done a basic proof of concenpt (POC), which is also attached. I
would appreciate some input on this. So far, I am simply dividing the list
equally and assigning them to worker processes. I intend to fine tune this
by taking into consideration file sizes. Further to add tar format support,
I am considering that each worker process, processes all files belonging to
a tablespace in its list (i.e. creates and copies tar file), before it
processes the next tablespace. As a result, this will create tar files that
are disjointed with respect tablespace data. For example:

Say, tablespace t1 has 20 files and we have 5 worker processes and
tablespace t2 has 10. Ignoring all other factors for the sake of this
example, each worker process will get a group of 4 files of t1 and 2 files
of t2. Each process will create 2 tar files, one for t1 containing 4 files
and another for t2 containing 2 files.

Regards,
Asif

Attachments:

0001-Initial-POC-on-parallel-backup.patchapplication/octet-stream; name=0001-Initial-POC-on-parallel-backup.patchDownload
From ffa6d0946af34d78e59eb5b82f1572f2537fffeb Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 21 Aug 2019 18:35:45 +0500
Subject: [PATCH] Initial POC on parallel backup

---
 src/backend/replication/basebackup.c   | 765 +++++++++++++++++--------
 src/backend/replication/repl_gram.y    |  53 +-
 src/backend/replication/repl_scanner.l |   4 +
 src/bin/pg_basebackup/pg_basebackup.c  | 285 ++++++++-
 src/include/nodes/replnodes.h          |   8 +
 5 files changed, 865 insertions(+), 250 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index c91f66dcbe..9cbee408ff 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -52,11 +52,26 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	bool		parallel;
 } basebackup_options;
 
+typedef struct
+{
+	bool		isdir;
+	char		*path;
+} pathinfo;
+
+#define MAKE_PATHINFO(a, b)	\
+	do {								\
+		pi = palloc0(sizeof(pathinfo));	\
+		pi->isdir = a;					\
+		pi->path = pstrdup(b);			\
+	} while(0)
 
 static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
 					 List *tablespaces, bool sendtblspclinks);
+static int64 sendDir_(const char *path, int basepathlen, bool sizeonly,
+					  List *tablespaces, bool sendtblspclinks, List **files);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -74,12 +89,18 @@ static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StopBackup(basebackup_options *opt);
+static void SendBackupFileList(List *tablespaces);
+static void SendFilesContents(List *files, bool missing_ok);
+static void includeWALFiles(basebackup_options *opt, XLogRecPtr endptr, TimeLineID endtli);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
 /* Relative path of temporary statistics directory */
 static char *statrelpath = NULL;
 
+#define TMP_BACKUP_LABEL_FILE BACKUP_LABEL_FILE".tmp"
 /*
  * Size of each block sent into the tar stream for larger files.
  */
@@ -305,6 +326,33 @@ perform_base_backup(basebackup_options *opt)
 			throttling_counter = -1;
 		}
 
+		/*
+		 * In the parallel mode, we will not be closing the backup or sending the files right away.
+		 * Instead we will only send the list of file names in the $PGDATA direcotry.
+		 */
+		if (opt->parallel)
+		{
+			/* save backup label into temp file for now. So stop backup can send it to pg_basebackup later on. */
+			FILE       *fp = AllocateFile(TMP_BACKUP_LABEL_FILE, "w");
+			if (!fp)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not create file \"%s\": %m",
+								TMP_BACKUP_LABEL_FILE)));
+			if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
+				fflush(fp) != 0 ||
+				pg_fsync(fileno(fp)) != 0 ||
+				ferror(fp) ||
+				FreeFile(fp))
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not write file \"%s\": %m",
+								TMP_BACKUP_LABEL_FILE)));
+
+			SendBackupFileList(tablespaces);
+			return;
+		}
+
 		/* Send off our tablespaces one by one */
 		foreach(lc, tablespaces)
 		{
@@ -367,234 +415,8 @@ perform_base_backup(basebackup_options *opt)
 
 
 	if (opt->includewal)
-	{
-		/*
-		 * We've left the last tar file "open", so we can now append the
-		 * required WAL files to it.
-		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
+		includeWALFiles(opt, endptr, endtli);
 
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/* Send CopyDone message for the last tar file */
-		pq_putemptymessage('c');
-	}
 	SendXlogRecPtrResult(endptr, endtli);
 
 	if (total_checksum_failures)
@@ -638,6 +460,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_parallel = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -726,6 +549,16 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			if (o_parallel)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			opt->parallel = true;
+			o_parallel = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -760,7 +593,12 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	if (cmd->cmdtag == SEND_FILES_CONTENT)
+		SendFilesContents(cmd->backupfiles, true);
+	else if (cmd->cmdtag == STOP_BACKUP)
+		StopBackup(&opt);
+	else
+		perform_base_backup(&opt);
 }
 
 static void
@@ -1004,9 +842,16 @@ sendTablespace(char *path, bool sizeonly)
  * information in the tar file. If not, we can skip that
  * as it will be sent separately in the tablespace_map file.
  */
+
+static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
+					  List *tablespaces, bool sendtblspclinks)
+{
+	return sendDir_(path, basepathlen, sizeonly, tablespaces, sendtblspclinks, NULL);
+}
+
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
-		bool sendtblspclinks)
+sendDir_(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+		bool sendtblspclinks, List **files)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -1160,6 +1005,15 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				if (files != NULL)
+				{
+					pathinfo *pi;
+
+					MAKE_PATHINFO(true, pathbuf);
+					*files = lappend(*files, pi);
+				}
+
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 				excludeFound = true;
 				break;
@@ -1197,6 +1051,13 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									sizeonly);
 
+			if (files != NULL)
+			{
+				pathinfo *pi;
+
+				MAKE_PATHINFO(true, pathbuf);
+				*files = lappend(*files, pi);
+			}
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -1282,13 +1143,29 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+			{
+				if (files != NULL)
+				{
+					pathinfo *pi;
+
+					MAKE_PATHINFO(true, pathbuf);
+					*files = lappend(*files, pi);
+				}
+				size += sendDir_(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks, files);
+			}
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			if (files != NULL)
+			{
+				pathinfo *pi;
+
+				MAKE_PATHINFO(false, pathbuf);
+				*files = lappend(*files, pi);
+			}
+			else if (!sizeonly)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1711,3 +1588,427 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID    endtli;
+	XLogRecPtr    endptr;
+	char *labelfile;
+	struct stat statbuf;
+	int            r;
+	StringInfoData buf;
+
+	/* Disable throttling. */
+	throttling_counter = -1;
+
+	/* send backup_label.tmp and pg_control files */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);    /* overall format */
+	pq_sendint16(&buf, 0);    /* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(TMP_BACKUP_LABEL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						TMP_BACKUP_LABEL_FILE)));
+	sendFile(TMP_BACKUP_LABEL_FILE, BACKUP_LABEL_FILE, &statbuf, false, InvalidOid);
+
+	/* read backup_label file into buffer, we need it for do_pg_stop_backup */
+	FILE *lfp = AllocateFile(TMP_BACKUP_LABEL_FILE, "r");
+	if (!lfp)
+	{
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not read file \"%s\": %m",
+						TMP_BACKUP_LABEL_FILE)));
+	}
+
+	labelfile = palloc(statbuf.st_size + 1);
+	r = fread(labelfile, statbuf.st_size, 1, lfp);
+	labelfile[statbuf.st_size] = '\0';
+
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	pq_putemptymessage('c');    /* CopyDone */
+
+	/* stop backup */
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	/*
+	 * FIXME: opt->includewal is not avaiable here. so just calling it unconditionaly. but should add
+	 *		includewal option to STOP_BACKUP command that pg_basebacup sends.
+	 */
+
+	//	if (opt->includewal)
+	includeWALFiles(opt, endptr, endtli);
+
+	/* send ending wal record. */
+	SendXlogRecPtrResult(endptr, endtli);
+}
+
+static void
+SendBackupFileList(List *tablespaces)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+
+	List *files = NIL;
+	foreach(lc, tablespaces)
+	{
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+		if (ti->path == NULL)
+			sendDir_(".", 1, false, NIL, true, &files);
+		else
+			sendDir_(ti->path, 1, false, NIL, true, &files);
+	}
+
+	// add backup label file
+	pathinfo *pi;
+	MAKE_PATHINFO(false, TMP_BACKUP_LABEL_FILE);
+	files = lcons(pi, files);
+
+	/* Construct and send the directory information */
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);        /* 2 fields */
+
+	/* First field - isdirectory */
+	pq_sendstring(&buf, "isDir");
+	pq_sendint32(&buf, 0);        /* table oid */
+	pq_sendint16(&buf, 0);        /* attnum */
+	pq_sendint32(&buf, INT4OID); /* type oid */
+	pq_sendint16(&buf, 4);        /* typlen */
+	pq_sendint32(&buf, 0);        /* typmod */
+	pq_sendint16(&buf, 0);        /* format code */
+
+	/* Second field - file path */
+	pq_sendstring(&buf, "path");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, TEXTOID);
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_endmessage(&buf);
+
+	foreach(lc, files)
+	{
+		pathinfo *pi = (pathinfo *) lfirst(lc);
+		char   *path = pi->path;
+
+		/* Send one datarow message */
+		pq_beginmessage(&buf, 'D');
+		pq_sendint16(&buf, 2);    /* number of columns */
+
+		int32 isdir = pi->isdir ? 1 : 0;
+		send_int8_string(&buf, isdir);
+
+		Size len = strlen(path);
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, path, len);
+
+		pq_endmessage(&buf);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+ }
+
+static void
+SendFilesContents(List *files, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell *lc;
+
+	/* Disable throttling. */
+	throttling_counter = -1;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);    /* overall format */
+	pq_sendint16(&buf, 0);    /* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, files)
+	{
+		Value *strval = lfirst(lc);
+		char   *pathbuf = (char *) strVal(strval);
+
+		// send file
+		struct stat statbuf;
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/*
+		 * TODO: perhaps create directory entry in the tar file, to avoid the need of manually creating
+		 *		directories in pg_basebackup.c
+		 */
+//		if (S_ISDIR(statbuf.st_mode))
+//		{
+//			bool		skip_this_dir = false;
+//			ListCell   *lc;
+//
+//			/*
+//			 * Store a directory entry in the tar file so we can get the
+//			 * permissions right.
+//			 */
+//
+//			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+//		}
+		sendFile(pathbuf, pathbuf, &statbuf, true, InvalidOid);
+	}
+
+	pq_putemptymessage('c');    /* CopyDone */
+	return;
+}
+
+static void
+includeWALFiles(basebackup_options *opt, XLogRecPtr endptr, TimeLineID endtli)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the
+	 * required WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and
+	 * include all WAL files in the range between 'startptr' and 'endptr',
+	 * regardless of the timeline the file is stamped with. If there are
+	 * some spurious WAL files belonging to timelines that don't belong in
+	 * this server's history, they will be included too. Normally there
+	 * shouldn't be such files, but if there are, there's little harm in
+	 * including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we
+	 * need were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from
+	 * oldest to newest, to reduce the chance that a file is recycled
+	 * before we get a chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since
+	 * we are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again
+		 * after promotion of a new node. This is in line with
+		 * walreceiver.c always doing an XLogArchiveForceDone() after a
+		 * complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history
+	 * file is required for recovery, and even that only if there happens
+	 * to be a timeline switch in the first WAL segment that contains the
+	 * checkpoint record, or if we're taking a base backup from a standby
+	 * server and the target timeline changes while the backup is taken.
+	 * But they are small and highly useful for debugging purposes, so
+	 * better include them all, always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/* Send CopyDone message for the last tar file */
+	pq_putemptymessage('c');
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..56b6934e43 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,6 +87,10 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_PARALLEL
+%token K_START_BACKUP
+%token K_SEND_FILES_CONTENT
+%token K_STOP_BACKUP
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
@@ -102,6 +106,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -155,13 +161,29 @@ var_name:	IDENT	{ $$ = $1; }
 
 /*
  * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
- * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS]
+ * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS] [PARALLEL]
  */
 base_backup:
 			K_BASE_BACKUP base_backup_opt_list
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILES_CONTENT backup_files
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = NIL;
+					cmd->cmdtag = SEND_FILES_CONTENT;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = NIL;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
@@ -214,6 +236,35 @@ base_backup_opt:
 				  $$ = makeDefElem("noverify_checksums",
 								   (Node *)makeInteger(true), -1);
 				}
+			| K_PARALLEL
+				{
+					$$ = makeDefElem("parallel",
+									(Node *)makeInteger(true), -1);
+				}
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{
+					$$ = $2;
+				}
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
+				{
+					$$ = list_make1($1);
+				}
+			| backup_files_list ',' backup_file
+				{
+					$$ = lappend($1, $3);
+				}
+			;
+
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..87a38046c0 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,10 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+PARALLEL			{ return K_PARALLEL; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_FILES_CONTENT	{ return K_SEND_FILES_CONTENT; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 9207109ba3..ed58d06316 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -40,6 +40,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -105,6 +106,7 @@ static bool temp_replication_slot = true;
 static bool create_slot = false;
 static bool no_slot = false;
 static bool verify_checksums = true;
+static int  numWorkers = 1;
 
 static bool success = false;
 static bool made_new_pgdata = false;
@@ -114,6 +116,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+PGconn		**conn_list = NULL;
+int			*worker_process;
+
 /* Progress counters */
 static uint64 totalsize;
 static uint64 totaldone;
@@ -157,6 +162,11 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupEnd(void);
+static int getFiles(SimpleStringList *files);
+static SimpleStringList** divideFilesList(SimpleStringList *files, int numFiles);
+static void create_workers_and_fetch(SimpleStringList **worker_files);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -355,6 +365,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -1477,6 +1488,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 			 */
 			snprintf(filename, sizeof(filename), "%s/%s", current_path,
 					 copybuf);
+
 			if (filename[strlen(filename) - 1] == '/')
 			{
 				/*
@@ -1867,7 +1879,23 @@ BaseBackup(void)
 			fprintf(stderr, "\n");
 	}
 
-	basebkp =
+	if (numWorkers > 1)
+	{
+		basebkp =
+		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s %s",
+				 escaped_label,
+				 showprogress ? "PROGRESS" : "",
+				 includewal == FETCH_WAL ? "WAL" : "",
+				 fastcheckpoint ? "FAST" : "",
+				 includewal == NO_WAL ? "" : "NOWAIT",
+				 maxrate_clause ? maxrate_clause : "",
+				 format == 't' ? "TABLESPACE_MAP" : "",
+				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS",
+				 (numWorkers > 1) ? "PARALLEL" : "");
+	}
+	else
+	{
+		basebkp =
 		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
@@ -1877,6 +1905,8 @@ BaseBackup(void)
 				 maxrate_clause ? maxrate_clause : "",
 				 format == 't' ? "TABLESPACE_MAP" : "",
 				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	}
+
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
@@ -1982,24 +2012,87 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		SimpleStringList files = {NULL, NULL};
+		SimpleStringList **worker_files;
 
-	if (showprogress)
-	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
+		/*
+		 * Get the header
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		int num_files = 0;
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			bool isdir = atoi(PQgetvalue(res, i, 0));
+			const char *path = PQgetvalue(res, i, 1);
+
+			/* create directories while traversing */
+			if (isdir)
+			{
+				bool created;
+				bool found;
+				char current_path[MAXPGPATH];
+
+				if (includewal == STREAM_WAL &&
+					(pg_str_endswith(path, "/pg_wal") ||
+					pg_str_endswith(path, "/pg_xlog") ||
+					pg_str_endswith(path, "/archive_status")))
+					continue;
+
+				snprintf(current_path, sizeof(current_path), "%s/%s", basedir, path + 2);
+				verify_dir_is_empty_or_create(current_path, &created, &found);
+			}
+
+			else
+			{
+				num_files++;
+				simple_string_list_append(&files, path);
+			}
+		}
+
+		res = PQgetResult(conn); //NoData
+		res = PQgetResult(conn); //CopyDone
+
+		worker_files = divideFilesList(&files, num_files);
+		create_workers_and_fetch(worker_files);
+
+		pg_log_info("total files in $PGDTA: %d", num_files);
+
+		ParallelBackupEnd();
 	}
+	else
+	{
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}							/* Loop over all tablespaces */
 
+		if (showprogress)
+		{
+			progress_report(PQntuples(res), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
+	}
 	PQclear(res);
 
 	/*
@@ -2195,6 +2288,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2222,7 +2316,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2363,6 +2457,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':		/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2477,6 +2574,22 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (numWorkers > 1 && format != 'p')
+	{
+		pg_log_error("Worker can only be specified in plain mode");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2545,7 +2658,145 @@ main(int argc, char **argv)
 	}
 
 	BaseBackup();
-
 	success = true;
 	return 0;
 }
+
+static void
+ParallelBackupEnd(void)
+{
+	PGresult   *res = NULL;
+	int			i = 0;
+	char       *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP"); /* FIXME: add "WAL" to the command, to handle -X FETCH command option. */
+
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive backup_label and pg_control files */
+	ReceiveAndUnpackTarFile(conn, res, i);
+	PQclear(res);
+}
+
+static int
+getFiles(SimpleStringList *files)
+{
+	SimpleStringListCell *cell;
+	PGresult   *res = NULL;
+	int i = 0;
+
+	PQExpBuffer buf;
+	buf = createPQExpBuffer();
+
+	/* build query in form of: SEND_FILES_CONTENT ('base/1/1245/32683', 'base/1/1245/32683', ...) */
+	appendPQExpBuffer(buf, "SEND_FILES_CONTENT ( ");
+	for (cell = files->head; cell; cell = cell->next)
+	{
+		char *str = cell->val; // skip './'
+
+		if (str == NULL)
+			continue;
+
+		if (str[0] == '.' && str[1] == '/')
+			str += 2;
+
+		i++;
+		if (cell != files->tail)
+			appendPQExpBuffer(buf, "'%s' ,", str);
+		else
+			appendPQExpBuffer(buf, "'%s'", str);
+	}
+	appendPQExpBufferStr(buf, " )");
+
+	PGconn *worker_conn = GetConnection();
+	if (!worker_conn)
+		return 1;
+
+
+	if (PQsendQuery(worker_conn, buf->data) == 0)
+	{
+		pg_log_error("could not send files list \"%s\"",
+					  PQerrorMessage(worker_conn));
+		return 1;
+	}
+	destroyPQExpBuffer(buf);
+
+//	if (format == 't')
+//		ReceiveTarFile(conn1, res, i);
+//	else
+		ReceiveAndUnpackTarFile(worker_conn, res, i);
+
+	res = PQgetResult(worker_conn); //NoData
+	res = PQgetResult(worker_conn); //CopyDone
+
+	PQclear(res);
+	PQfinish(worker_conn);
+
+	return 0;
+}
+
+static SimpleStringList**
+divideFilesList(SimpleStringList *files, int numFiles)
+{
+	SimpleStringList **worker_files;
+	SimpleStringListCell *cell;
+	int file_per_worker = (numFiles / numWorkers) + 1;
+	int cnt = 0, i = 0;
+
+	/* init worker_files */
+	worker_files = (SimpleStringList**) palloc0(sizeof(SimpleStringList) * numWorkers);
+	for (i = 0; i < numWorkers; i++)
+		worker_files[i] = (SimpleStringList*) palloc0(sizeof(SimpleStringList));
+
+	/* copy file to worker_files[] */
+	i = 0;
+	for (cell = files->head; cell; cell = cell->next)
+	{
+		if (i >= file_per_worker)
+		{
+			printf("%d files for worker %d\n", i, cnt);
+			cnt ++;
+			i = 0;
+		}
+
+		simple_string_list_append(worker_files[cnt], cell->val);
+		i++;
+	}
+
+	return worker_files;
+}
+
+
+static void
+create_workers_and_fetch(SimpleStringList **worker_files)
+{
+	worker_process = (int*) palloc(sizeof(int) * numWorkers);
+	int status;
+	int pid, i;
+	for (i = 0; i < numWorkers; i++)
+	{
+		worker_process[i] = fork();
+		if (worker_process[i] == 0)
+		{
+			/* in child process */
+			_exit(getFiles(worker_files[i]));
+		}
+		else if (worker_process[i] < 0)
+		{
+			pg_log_error("could not create background process: %m");
+			exit(1);
+		}
+
+		pg_log_info("process (%d) created", worker_process[i]);
+		/*
+		 * Else we are in the parent process and all is well.
+		 */
+	}
+
+	while (waitpid(-1, NULL, WNOHANG) > 0);
+}
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..b4127864c2 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,12 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	SEND_FILES_CONTENT,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +48,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
-- 
2.20.1 (Apple Git-117)

#2Asim R P
apraveen@pivotal.io
In reply to: Asif Rehman (#1)
Re: WIP/PoC for parallel backup

Hi Asif

Interesting proposal. Bulk of the work in a backup is transferring files
from source data directory to destination. Your patch is breaking this
task down in multiple sets of files and transferring each set in parallel.
This seems correct, however, your patch is also creating a new process to
handle each set. Is that necessary? I think we should try to achieve this
using multiple asynchronous libpq connections from a single basebackup
process. That is to use PQconnectStartParams() interface instead of
PQconnectdbParams(), wich is currently used by basebackup. On the server
side, it may still result in multiple backend processes per connection, and
an attempt should be made to avoid that as well, but it seems complicated.

What do you think?

Asim

#3Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Asim R P (#2)
Re: WIP/PoC for parallel backup

On Fri, Aug 23, 2019 at 3:18 PM Asim R P <apraveen@pivotal.io> wrote:

Hi Asif

Interesting proposal. Bulk of the work in a backup is transferring files
from source data directory to destination. Your patch is breaking this
task down in multiple sets of files and transferring each set in parallel.
This seems correct, however, your patch is also creating a new process to
handle each set. Is that necessary? I think we should try to achieve this
using multiple asynchronous libpq connections from a single basebackup
process. That is to use PQconnectStartParams() interface instead of
PQconnectdbParams(), wich is currently used by basebackup. On the server
side, it may still result in multiple backend processes per connection, and
an attempt should be made to avoid that as well, but it seems complicated.

What do you think?

The main question is what we really want to solve here. What is the

bottleneck? and which HW want to saturate?. Why I am saying that because
there are multiple H/W involve while taking the backup (Network/CPU/Disk).
If we
already saturated the disk then there is no need to add parallelism because
we will be blocked on disk I/O anyway. I implemented the parallel backup
in a sperate
application and has wonderful results. I just skim through the code and have
some reservation that creating a separate process only for copying data is
overkill.
There are two options, one is non-blocking calls or you can have some
worker threads.
But before doing that need to see the pg_basebackup bottleneck, after that,
we
can see what is the best way to solve that. Some numbers may help to
understand the
actual benefit.

--
Ibrar Ahmed

#4Asif Rehman
asifr.rehman@gmail.com
In reply to: Asim R P (#2)
Re: WIP/PoC for parallel backup

On Fri, Aug 23, 2019 at 3:18 PM Asim R P <apraveen@pivotal.io> wrote:

Hi Asif

Interesting proposal. Bulk of the work in a backup is transferring files
from source data directory to destination. Your patch is breaking this
task down in multiple sets of files and transferring each set in parallel.
This seems correct, however, your patch is also creating a new process to
handle each set. Is that necessary? I think we should try to achieve this
using multiple asynchronous libpq connections from a single basebackup
process. That is to use PQconnectStartParams() interface instead of
PQconnectdbParams(), wich is currently used by basebackup. On the server
side, it may still result in multiple backend processes per connection, and
an attempt should be made to avoid that as well, but it seems complicated.

What do you think?

Asim

Thanks Asim for the feedback. This is a good suggestion. The main idea I
wanted to discuss is the design where we can open multiple backend
connections to get the data instead of a single connection.
On the client side we can have multiple approaches, One is to use
asynchronous APIs ( as suggested by you) and other could be to decide
between multi-process and multi-thread. The main point was we can extract
lot of performance benefit by using the multiple connections and I built
this POC to float the idea of how the parallel backup can work, since the
core logic of getting the files using multiple connections will remain the
same, wether we use asynchronous, multi-process or multi-threaded.

I am going to address the division of files to be distributed evenly among
multiple workers based on file sizes, that would allow to get some concrete
numbers as well as it will also us to gauge some benefits between async and
multiprocess/thread approach on client side.

Regards,
Asif

#5Stephen Frost
sfrost@snowman.net
In reply to: Asif Rehman (#4)
Re: WIP/PoC for parallel backup

Greetings,

* Asif Rehman (asifr.rehman@gmail.com) wrote:

On Fri, Aug 23, 2019 at 3:18 PM Asim R P <apraveen@pivotal.io> wrote:

Interesting proposal. Bulk of the work in a backup is transferring files
from source data directory to destination. Your patch is breaking this
task down in multiple sets of files and transferring each set in parallel.
This seems correct, however, your patch is also creating a new process to
handle each set. Is that necessary? I think we should try to achieve this
using multiple asynchronous libpq connections from a single basebackup
process. That is to use PQconnectStartParams() interface instead of
PQconnectdbParams(), wich is currently used by basebackup. On the server
side, it may still result in multiple backend processes per connection, and
an attempt should be made to avoid that as well, but it seems complicated.

Thanks Asim for the feedback. This is a good suggestion. The main idea I
wanted to discuss is the design where we can open multiple backend
connections to get the data instead of a single connection.
On the client side we can have multiple approaches, One is to use
asynchronous APIs ( as suggested by you) and other could be to decide
between multi-process and multi-thread. The main point was we can extract
lot of performance benefit by using the multiple connections and I built
this POC to float the idea of how the parallel backup can work, since the
core logic of getting the files using multiple connections will remain the
same, wether we use asynchronous, multi-process or multi-threaded.

I am going to address the division of files to be distributed evenly among
multiple workers based on file sizes, that would allow to get some concrete
numbers as well as it will also us to gauge some benefits between async and
multiprocess/thread approach on client side.

I would expect you to quickly want to support compression on the server
side, before the data is sent across the network, and possibly
encryption, and so it'd likely make sense to just have independent
processes and connections through which to do that.

Thanks,

Stephen

#6Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Stephen Frost (#5)
Re: WIP/PoC for parallel backup

On Fri, Aug 23, 2019 at 10:26 PM Stephen Frost <sfrost@snowman.net> wrote:

Greetings,

* Asif Rehman (asifr.rehman@gmail.com) wrote:

On Fri, Aug 23, 2019 at 3:18 PM Asim R P <apraveen@pivotal.io> wrote:

Interesting proposal. Bulk of the work in a backup is transferring

files

from source data directory to destination. Your patch is breaking this
task down in multiple sets of files and transferring each set in

parallel.

This seems correct, however, your patch is also creating a new process

to

handle each set. Is that necessary? I think we should try to achieve

this

using multiple asynchronous libpq connections from a single basebackup
process. That is to use PQconnectStartParams() interface instead of
PQconnectdbParams(), wich is currently used by basebackup. On the

server

side, it may still result in multiple backend processes per

connection, and

an attempt should be made to avoid that as well, but it seems

complicated.

Thanks Asim for the feedback. This is a good suggestion. The main idea I
wanted to discuss is the design where we can open multiple backend
connections to get the data instead of a single connection.
On the client side we can have multiple approaches, One is to use
asynchronous APIs ( as suggested by you) and other could be to decide
between multi-process and multi-thread. The main point was we can extract
lot of performance benefit by using the multiple connections and I built
this POC to float the idea of how the parallel backup can work, since the
core logic of getting the files using multiple connections will remain

the

same, wether we use asynchronous, multi-process or multi-threaded.

I am going to address the division of files to be distributed evenly

among

multiple workers based on file sizes, that would allow to get some

concrete

numbers as well as it will also us to gauge some benefits between async

and

multiprocess/thread approach on client side.

I would expect you to quickly want to support compression on the server
side, before the data is sent across the network, and possibly
encryption, and so it'd likely make sense to just have independent
processes and connections through which to do that.

+1 for compression and encryption, but I think parallelism will give us

the benefit with and without the compression.

Thanks,

Stephen

--
Ibrar Ahmed

#7Ahsan Hadi
ahsan.hadi@gmail.com
In reply to: Stephen Frost (#5)
Re: WIP/PoC for parallel backup

On Fri, 23 Aug 2019 at 10:26 PM, Stephen Frost <sfrost@snowman.net> wrote:

Greetings,

* Asif Rehman (asifr.rehman@gmail.com) wrote:

On Fri, Aug 23, 2019 at 3:18 PM Asim R P <apraveen@pivotal.io> wrote:

Interesting proposal. Bulk of the work in a backup is transferring

files

from source data directory to destination. Your patch is breaking this
task down in multiple sets of files and transferring each set in

parallel.

This seems correct, however, your patch is also creating a new process

to

handle each set. Is that necessary? I think we should try to achieve

this

using multiple asynchronous libpq connections from a single basebackup
process. That is to use PQconnectStartParams() interface instead of
PQconnectdbParams(), wich is currently used by basebackup. On the

server

side, it may still result in multiple backend processes per

connection, and

an attempt should be made to avoid that as well, but it seems

complicated.

Thanks Asim for the feedback. This is a good suggestion. The main idea I
wanted to discuss is the design where we can open multiple backend
connections to get the data instead of a single connection.
On the client side we can have multiple approaches, One is to use
asynchronous APIs ( as suggested by you) and other could be to decide
between multi-process and multi-thread. The main point was we can extract
lot of performance benefit by using the multiple connections and I built
this POC to float the idea of how the parallel backup can work, since the
core logic of getting the files using multiple connections will remain

the

same, wether we use asynchronous, multi-process or multi-threaded.

I am going to address the division of files to be distributed evenly

among

multiple workers based on file sizes, that would allow to get some

concrete

numbers as well as it will also us to gauge some benefits between async

and

multiprocess/thread approach on client side.

I would expect you to quickly want to support compression on the server
side, before the data is sent across the network, and possibly
encryption, and so it'd likely make sense to just have independent
processes and connections through which to do that.

It would be interesting to see the benefits of compression (before the data
is transferred over the network) on top of parallelism. Since there is also
some overhead associated with performing the compression. I agree with your
suggestion of trying to add parallelism first and then try compression
before the data is sent across the network.

Show quoted text

Thanks,

Stephen

#8Stephen Frost
sfrost@snowman.net
In reply to: Ahsan Hadi (#7)
Re: WIP/PoC for parallel backup

Greetings,

* Ahsan Hadi (ahsan.hadi@gmail.com) wrote:

On Fri, 23 Aug 2019 at 10:26 PM, Stephen Frost <sfrost@snowman.net> wrote:

I would expect you to quickly want to support compression on the server
side, before the data is sent across the network, and possibly
encryption, and so it'd likely make sense to just have independent
processes and connections through which to do that.

It would be interesting to see the benefits of compression (before the data
is transferred over the network) on top of parallelism. Since there is also
some overhead associated with performing the compression. I agree with your
suggestion of trying to add parallelism first and then try compression
before the data is sent across the network.

You're welcome to take a look at pgbackrest for insight and to play with
regarding compression-before-transfer, how best to split up the files
and order them, encryption, et al. We've put quite a bit of effort into
figuring all of that out.

Thanks!

Stephen

#9Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#1)
Re: WIP/PoC for parallel backup

On Wed, Aug 21, 2019 at 9:53 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

- BASE_BACKUP [PARALLEL] - returns a list of files in PGDATA
If the parallel option is there, then it will only do pg_start_backup, scans PGDATA and sends a list of file names.

So IIUC, this would mean that BASE_BACKUP without PARALLEL returns
tarfiles, and BASE_BACKUP with PARALLEL returns a result set with a
list of file names. I don't think that's a good approach. It's too
confusing to have one replication command that returns totally
different things depending on whether some option is given.

- SEND_FILES_CONTENTS (file1, file2,...) - returns the files in given list.
pg_basebackup will then send back a list of filenames in this command. This commands will be send by each worker and that worker will be getting the said files.

Seems reasonable, but I think you should just pass one file name and
use the command multiple times, once per file.

- STOP_BACKUP
when all workers finish then, pg_basebackup will send STOP_BACKUP command.

This also seems reasonable, but surely the matching command should
then be called START_BACKUP, not BASEBACKUP PARALLEL.

I have done a basic proof of concenpt (POC), which is also attached. I would appreciate some input on this. So far, I am simply dividing the list equally and assigning them to worker processes. I intend to fine tune this by taking into consideration file sizes. Further to add tar format support, I am considering that each worker process, processes all files belonging to a tablespace in its list (i.e. creates and copies tar file), before it processes the next tablespace. As a result, this will create tar files that are disjointed with respect tablespace data. For example:

Instead of doing this, I suggest that you should just maintain a list
of all the files that need to be fetched and have each worker pull a
file from the head of the list and fetch it when it finishes receiving
the previous file. That way, if some connections go faster or slower
than others, the distribution of work ends up fairly even. If you
instead pre-distribute the work, you're guessing what's going to
happen in the future instead of just waiting to see what actually does
happen. Guessing isn't intrinsically bad, but guessing when you could
be sure of doing the right thing *is* bad.

If you want to be really fancy, you could start by sorting the files
in descending order of size, so that big files are fetched before
small ones. Since the largest possible file is 1GB and any database
where this feature is important is probably hundreds or thousands of
GB, this may not be very important. I suggest not worrying about it
for v1.

Say, tablespace t1 has 20 files and we have 5 worker processes and tablespace t2 has 10. Ignoring all other factors for the sake of this example, each worker process will get a group of 4 files of t1 and 2 files of t2. Each process will create 2 tar files, one for t1 containing 4 files and another for t2 containing 2 files.

This is one of several possible approaches. If we're doing a
plain-format backup in parallel, we can just write each file where it
needs to go and call it good. But, with a tar-format backup, what
should we do? I can see three options:

1. Error! Tar format parallel backups are not supported.

2. Write multiple tar files. The user might reasonably expect that
they're going to end up with the same files at the end of the backup
regardless of whether they do it in parallel. A user with this
expectation will be disappointed.

3. Write one tar file. In this design, the workers have to take turns
writing to the tar file, so you need some synchronization around that.
Perhaps you'd have N threads that read and buffer a file, and N+1
buffers. Then you have one additional thread that reads the complete
files from the buffers and writes them to the tar file. There's
obviously some possibility that the writer won't be able to keep up
and writing the backup will therefore be slower than it would be with
approach (2).

There's probably also a possibility that approach (2) would thrash the
disk head back and forth between multiple files that are all being
written at the same time, and approach (3) will therefore win by not
thrashing the disk head. But, since spinning media are becoming less
and less popular and are likely to have multiple disk heads under the
hood when they are used, this is probably not too likely.

I think your choice to go with approach (2) is probably reasonable,
but I'm not sure whether everyone will agree.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#10Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#9)
Re: WIP/PoC for parallel backup

Hi Robert,

Thanks for the feedback. Please see the comments below:

On Tue, Sep 24, 2019 at 10:53 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Aug 21, 2019 at 9:53 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

- BASE_BACKUP [PARALLEL] - returns a list of files in PGDATA
If the parallel option is there, then it will only do pg_start_backup,

scans PGDATA and sends a list of file names.

So IIUC, this would mean that BASE_BACKUP without PARALLEL returns
tarfiles, and BASE_BACKUP with PARALLEL returns a result set with a
list of file names. I don't think that's a good approach. It's too
confusing to have one replication command that returns totally
different things depending on whether some option is given.

Sure. I will add a separate command (START_BACKUP) for parallel.

- SEND_FILES_CONTENTS (file1, file2,...) - returns the files in given

list.

pg_basebackup will then send back a list of filenames in this command.

This commands will be send by each worker and that worker will be getting
the said files.

Seems reasonable, but I think you should just pass one file name and
use the command multiple times, once per file.

I considered this approach initially, however, I adopted the current
strategy to avoid multiple round trips between the server and clients and
save on query processing time by issuing a single command rather than
multiple ones. Further fetching multiple files at once will also aid in
supporting the tar format by utilising the existing ReceiveTarFile()
function and will be able to create a tarball for per tablespace per worker.

- STOP_BACKUP
when all workers finish then, pg_basebackup will send STOP_BACKUP

command.

This also seems reasonable, but surely the matching command should
then be called START_BACKUP, not BASEBACKUP PARALLEL.

I have done a basic proof of concenpt (POC), which is also attached. I

would appreciate some input on this. So far, I am simply dividing the list
equally and assigning them to worker processes. I intend to fine tune this
by taking into consideration file sizes. Further to add tar format support,
I am considering that each worker process, processes all files belonging to
a tablespace in its list (i.e. creates and copies tar file), before it
processes the next tablespace. As a result, this will create tar files that
are disjointed with respect tablespace data. For example:

Instead of doing this, I suggest that you should just maintain a list
of all the files that need to be fetched and have each worker pull a
file from the head of the list and fetch it when it finishes receiving
the previous file. That way, if some connections go faster or slower
than others, the distribution of work ends up fairly even. If you
instead pre-distribute the work, you're guessing what's going to
happen in the future instead of just waiting to see what actually does
happen. Guessing isn't intrinsically bad, but guessing when you could
be sure of doing the right thing *is* bad.

If you want to be really fancy, you could start by sorting the files
in descending order of size, so that big files are fetched before
small ones. Since the largest possible file is 1GB and any database
where this feature is important is probably hundreds or thousands of
GB, this may not be very important. I suggest not worrying about it
for v1.

Ideally, I would like to support the tar format as well, which would be
much easier to implement when fetching multiple files at once since that
would enable using the existent functionality to be used without much
change.

Your idea of sorting the files in descending order of size seems very
appealing. I think we can do this and have the file divided among the
workers one by one i.e. the first file in the list goes to worker 1, the
second to process 2, and so on and so forth.

Say, tablespace t1 has 20 files and we have 5 worker processes and

tablespace t2 has 10. Ignoring all other factors for the sake of this
example, each worker process will get a group of 4 files of t1 and 2 files
of t2. Each process will create 2 tar files, one for t1 containing 4 files
and another for t2 containing 2 files.

This is one of several possible approaches. If we're doing a
plain-format backup in parallel, we can just write each file where it
needs to go and call it good. But, with a tar-format backup, what
should we do? I can see three options:

1. Error! Tar format parallel backups are not supported.

2. Write multiple tar files. The user might reasonably expect that
they're going to end up with the same files at the end of the backup
regardless of whether they do it in parallel. A user with this
expectation will be disappointed.

3. Write one tar file. In this design, the workers have to take turns
writing to the tar file, so you need some synchronization around that.
Perhaps you'd have N threads that read and buffer a file, and N+1
buffers. Then you have one additional thread that reads the complete
files from the buffers and writes them to the tar file. There's
obviously some possibility that the writer won't be able to keep up
and writing the backup will therefore be slower than it would be with
approach (2).

There's probably also a possibility that approach (2) would thrash the
disk head back and forth between multiple files that are all being
written at the same time, and approach (3) will therefore win by not
thrashing the disk head. But, since spinning media are becoming less
and less popular and are likely to have multiple disk heads under the
hood when they are used, this is probably not too likely.

I think your choice to go with approach (2) is probably reasonable,
but I'm not sure whether everyone will agree.

Yes for the tar format support, approach (2) is what I had in
mind. Currently I'm working on the implementation and will share the patch
in a couple of days.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#11Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Asif Rehman (#10)
1 attachment(s)
Re: WIP/PoC for parallel backup

Hi Asif,

I was looking at the patch and tried comipling it. However, got few errors
and warnings.

Fixed those in the attached patch.

On Fri, Sep 27, 2019 at 9:30 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Hi Robert,

Thanks for the feedback. Please see the comments below:

On Tue, Sep 24, 2019 at 10:53 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Wed, Aug 21, 2019 at 9:53 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

- BASE_BACKUP [PARALLEL] - returns a list of files in PGDATA
If the parallel option is there, then it will only do pg_start_backup,

scans PGDATA and sends a list of file names.

So IIUC, this would mean that BASE_BACKUP without PARALLEL returns
tarfiles, and BASE_BACKUP with PARALLEL returns a result set with a
list of file names. I don't think that's a good approach. It's too
confusing to have one replication command that returns totally
different things depending on whether some option is given.

Sure. I will add a separate command (START_BACKUP) for parallel.

- SEND_FILES_CONTENTS (file1, file2,...) - returns the files in given

list.

pg_basebackup will then send back a list of filenames in this command.

This commands will be send by each worker and that worker will be getting
the said files.

Seems reasonable, but I think you should just pass one file name and
use the command multiple times, once per file.

I considered this approach initially, however, I adopted the current
strategy to avoid multiple round trips between the server and clients and
save on query processing time by issuing a single command rather than
multiple ones. Further fetching multiple files at once will also aid in
supporting the tar format by utilising the existing ReceiveTarFile()
function and will be able to create a tarball for per tablespace per worker.

- STOP_BACKUP
when all workers finish then, pg_basebackup will send STOP_BACKUP

command.

This also seems reasonable, but surely the matching command should
then be called START_BACKUP, not BASEBACKUP PARALLEL.

I have done a basic proof of concenpt (POC), which is also attached. I

would appreciate some input on this. So far, I am simply dividing the list
equally and assigning them to worker processes. I intend to fine tune this
by taking into consideration file sizes. Further to add tar format support,
I am considering that each worker process, processes all files belonging to
a tablespace in its list (i.e. creates and copies tar file), before it
processes the next tablespace. As a result, this will create tar files that
are disjointed with respect tablespace data. For example:

Instead of doing this, I suggest that you should just maintain a list
of all the files that need to be fetched and have each worker pull a
file from the head of the list and fetch it when it finishes receiving
the previous file. That way, if some connections go faster or slower
than others, the distribution of work ends up fairly even. If you
instead pre-distribute the work, you're guessing what's going to
happen in the future instead of just waiting to see what actually does
happen. Guessing isn't intrinsically bad, but guessing when you could
be sure of doing the right thing *is* bad.

If you want to be really fancy, you could start by sorting the files
in descending order of size, so that big files are fetched before
small ones. Since the largest possible file is 1GB and any database
where this feature is important is probably hundreds or thousands of
GB, this may not be very important. I suggest not worrying about it
for v1.

Ideally, I would like to support the tar format as well, which would be
much easier to implement when fetching multiple files at once since that
would enable using the existent functionality to be used without much
change.

Your idea of sorting the files in descending order of size seems very
appealing. I think we can do this and have the file divided among the
workers one by one i.e. the first file in the list goes to worker 1, the
second to process 2, and so on and so forth.

Say, tablespace t1 has 20 files and we have 5 worker processes and

tablespace t2 has 10. Ignoring all other factors for the sake of this
example, each worker process will get a group of 4 files of t1 and 2 files
of t2. Each process will create 2 tar files, one for t1 containing 4 files
and another for t2 containing 2 files.

This is one of several possible approaches. If we're doing a
plain-format backup in parallel, we can just write each file where it
needs to go and call it good. But, with a tar-format backup, what
should we do? I can see three options:

1. Error! Tar format parallel backups are not supported.

2. Write multiple tar files. The user might reasonably expect that
they're going to end up with the same files at the end of the backup
regardless of whether they do it in parallel. A user with this
expectation will be disappointed.

3. Write one tar file. In this design, the workers have to take turns
writing to the tar file, so you need some synchronization around that.
Perhaps you'd have N threads that read and buffer a file, and N+1
buffers. Then you have one additional thread that reads the complete
files from the buffers and writes them to the tar file. There's
obviously some possibility that the writer won't be able to keep up
and writing the backup will therefore be slower than it would be with
approach (2).

There's probably also a possibility that approach (2) would thrash the
disk head back and forth between multiple files that are all being
written at the same time, and approach (3) will therefore win by not
thrashing the disk head. But, since spinning media are becoming less
and less popular and are likely to have multiple disk heads under the
hood when they are used, this is probably not too likely.

I think your choice to go with approach (2) is probably reasonable,
but I'm not sure whether everyone will agree.

Yes for the tar format support, approach (2) is what I had in
mind. Currently I'm working on the implementation and will share the patch
in a couple of days.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

Attachments:

0001-Initial-POC-on-parallel-backup_fix_errors_warnings_delta.patchtext/x-patch; charset=US-ASCII; name=0001-Initial-POC-on-parallel-backup_fix_errors_warnings_delta.patchDownload
commit 0d7433e44123b486b48f2071b24f1eaef46f4849
Author: Jeevan Chalke <jeevan.chalke@enterprisedb.com>
Date:   Thu Oct 3 12:58:55 2019 +0530

    Fix errors and warnings.

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index ef55bd0..32ed160 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -346,6 +346,7 @@ perform_base_backup(basebackup_options *opt)
 		{
 			/* save backup label into temp file for now. So stop backup can send it to pg_basebackup later on. */
 			FILE       *fp = AllocateFile(TMP_BACKUP_LABEL_FILE, "w");
+
 			if (!fp)
 				ereport(ERROR,
 						(errcode_for_file_access(),
@@ -1627,8 +1628,8 @@ StopBackup(basebackup_options *opt)
 	XLogRecPtr    endptr;
 	char *labelfile;
 	struct stat statbuf;
-	int            r;
 	StringInfoData buf;
+	FILE	   *lfp;
 
 	/* Disable throttling. */
 	throttling_counter = -1;
@@ -1648,7 +1649,7 @@ StopBackup(basebackup_options *opt)
 	sendFile(TMP_BACKUP_LABEL_FILE, BACKUP_LABEL_FILE, &statbuf, false, InvalidOid);
 
 	/* read backup_label file into buffer, we need it for do_pg_stop_backup */
-	FILE *lfp = AllocateFile(TMP_BACKUP_LABEL_FILE, "r");
+	lfp = AllocateFile(TMP_BACKUP_LABEL_FILE, "r");
 	if (!lfp)
 	{
 		ereport(ERROR,
@@ -1658,7 +1659,7 @@ StopBackup(basebackup_options *opt)
 	}
 
 	labelfile = palloc(statbuf.st_size + 1);
-	r = fread(labelfile, statbuf.st_size, 1, lfp);
+	fread(labelfile, statbuf.st_size, 1, lfp);
 	labelfile[statbuf.st_size] = '\0';
 
 
@@ -1692,6 +1693,7 @@ SendBackupFileList(List *tablespaces)
 {
 	StringInfoData buf;
 	ListCell   *lc;
+	pathinfo   *pi;
 
 	List *files = NIL;
 	foreach(lc, tablespaces)
@@ -1704,7 +1706,6 @@ SendBackupFileList(List *tablespaces)
 	}
 
 	// add backup label file
-	pathinfo *pi;
 	MAKE_PATHINFO(false, TMP_BACKUP_LABEL_FILE);
 	files = lcons(pi, files);
 
@@ -1736,15 +1737,15 @@ SendBackupFileList(List *tablespaces)
 	{
 		pathinfo *pi = (pathinfo *) lfirst(lc);
 		char   *path = pi->path;
+		Size		len;
 
 		/* Send one datarow message */
 		pq_beginmessage(&buf, 'D');
 		pq_sendint16(&buf, 2);    /* number of columns */
 
-		int32 isdir = pi->isdir ? 1 : 0;
-		send_int8_string(&buf, isdir);
+		send_int8_string(&buf, (pi->isdir ? 1 : 0));
 
-		Size len = strlen(path);
+		len = strlen(path);
 		pq_sendint32(&buf, len);
 		pq_sendbytes(&buf, path, len);
 
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 1637735..a316cc6 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -1864,6 +1864,7 @@ BaseBackup(void)
 	{
 		SimpleStringList files = {NULL, NULL};
 		SimpleStringList **worker_files;
+		int			num_files;
 
 		/*
 		 * Get the header
@@ -1881,7 +1882,7 @@ BaseBackup(void)
 			exit(1);
 		}
 
-		int num_files = 0;
+		num_files = 0;
 		for (i = 0; i < PQntuples(res); i++)
 		{
 			bool isdir = atoi(PQgetvalue(res, i, 0));
@@ -2537,6 +2538,7 @@ getFiles(SimpleStringList *files)
 	SimpleStringListCell *cell;
 	PGresult   *res = NULL;
 	int i = 0;
+	PGconn *worker_conn;
 
 	PQExpBuffer buf;
 	buf = createPQExpBuffer();
@@ -2561,7 +2563,7 @@ getFiles(SimpleStringList *files)
 	}
 	appendPQExpBufferStr(buf, " )");
 
-	PGconn *worker_conn = GetConnection();
+	worker_conn = GetConnection();
 	if (!worker_conn)
 		return 1;
 
@@ -2623,9 +2625,10 @@ divideFilesList(SimpleStringList *files, int numFiles)
 static void
 create_workers_and_fetch(SimpleStringList **worker_files)
 {
+	int			i;
+
 	worker_process = (int*) palloc(sizeof(int) * numWorkers);
-	int status;
-	int pid, i;
+
 	for (i = 0; i < numWorkers; i++)
 	{
 		worker_process[i] = fork();
#12Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#10)
Re: WIP/PoC for parallel backup

On Fri, Sep 27, 2019 at 12:00 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

- SEND_FILES_CONTENTS (file1, file2,...) - returns the files in given list.
pg_basebackup will then send back a list of filenames in this command. This commands will be send by each worker and that worker will be getting the said files.

Seems reasonable, but I think you should just pass one file name and
use the command multiple times, once per file.

I considered this approach initially, however, I adopted the current strategy to avoid multiple round trips between the server and clients and save on query processing time by issuing a single command rather than multiple ones. Further fetching multiple files at once will also aid in supporting the tar format by utilising the existing ReceiveTarFile() function and will be able to create a tarball for per tablespace per worker.

I think that sending multiple filenames on a line could save some time
when there are lots of very small files, because then the round-trip
overhead could be significant.

However, if you've got mostly big files, I think this is going to be a
loser. It'll be fine if you're able to divide the work exactly evenly,
but that's pretty hard to do, because some workers may succeed in
copying the data faster than others for a variety of reasons: some
data is in memory, some data has to be read from disk, different data
may need to be read from different disks that run at different speeds,
not all the network connections may run at the same speed. Remember
that the backup's not done until the last worker finishes, and so
there may well be a significant advantage in terms of overall speed in
putting some energy into making sure that they finish as close to each
other in time as possible.

To put that another way, the first time all the workers except one get
done while the last one still has 10GB of data to copy, somebody's
going to be unhappy.

Ideally, I would like to support the tar format as well, which would be much easier to implement when fetching multiple files at once since that would enable using the existent functionality to be used without much change.

I think we should just have the client generate the tarfile. It'll
require duplicating some code, but it's not actually that much code or
that complicated from what I can see.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#13Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#12)
1 attachment(s)
Re: WIP/PoC for parallel backup

On Thu, Oct 3, 2019 at 6:40 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Sep 27, 2019 at 12:00 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

- SEND_FILES_CONTENTS (file1, file2,...) - returns the files in given

list.

pg_basebackup will then send back a list of filenames in this

command. This commands will be send by each worker and that worker will be
getting the said files.

Seems reasonable, but I think you should just pass one file name and
use the command multiple times, once per file.

I considered this approach initially, however, I adopted the current

strategy to avoid multiple round trips between the server and clients and
save on query processing time by issuing a single command rather than
multiple ones. Further fetching multiple files at once will also aid in
supporting the tar format by utilising the existing ReceiveTarFile()
function and will be able to create a tarball for per tablespace per worker.

I think that sending multiple filenames on a line could save some time
when there are lots of very small files, because then the round-trip
overhead could be significant.

However, if you've got mostly big files, I think this is going to be a
loser. It'll be fine if you're able to divide the work exactly evenly,
but that's pretty hard to do, because some workers may succeed in
copying the data faster than others for a variety of reasons: some
data is in memory, some data has to be read from disk, different data
may need to be read from different disks that run at different speeds,
not all the network connections may run at the same speed. Remember
that the backup's not done until the last worker finishes, and so
there may well be a significant advantage in terms of overall speed in
putting some energy into making sure that they finish as close to each
other in time as possible.

To put that another way, the first time all the workers except one get
done while the last one still has 10GB of data to copy, somebody's
going to be unhappy.

I have updated the patch (see the attached patch) to include tablespace
support, tar format support and all other backup base backup options to
work in parallel mode as well. As previously suggested, I have removed
BASE_BACKUP [PARALLEL] and have added START_BACKUP instead to start the
backup. The tar format will write multiple tar files depending upon the
number of workers specified. Also made all commands
(START_BACKUP/SEND_FILES_CONTENT/STOP_BACKUP) to accept the
base_backup_opt_list. This way the command-line options can also be
provided to these commands. Since the command-line options don't change
once the backup initiates, I went this way instead of storing them in
shared state.

The START_BACKUP command will now return a sorted list of files in
descending order based on file sizes. This way, the larger files will be on
top of the list. hence these files will be assigned to workers one by one,
making it so that the larger files will be copied before other files.

Based on my understanding your main concern is that the files won't be
distributed fairly i.e one worker might get a big file and take more time
while others get done early with smaller files? In this approach I have
created a list of files in descending order based on there sizes so all the
big size files will come at the top. The maximum file size in PG is 1GB so
if we have four workers who are picking up file from the list one by one,
the worst case scenario is that one worker gets a file of 1GB to process
while others get files of smaller size. However with this approach of
descending files based on size and handing it out to workers one by one,
there is a very high likelihood of workers getting work evenly. does this
address your concerns?

Furthermore the patch also includes the regression test. As t/
010_pg_basebackup.pl test-case is testing base backup comprehensively, so I
have duplicated it to "t/040_pg_basebackup_parallel.pl" and added parallel
option in all of its tests, to make sure parallel mode works expectantly.
The one thing that differs from base backup is the file checksum reporting.
In parallel mode, the total number of checksum failures are not reported
correctly however it will abort the backup whenever a checksum failure
occurs. This is because processes are not maintaining any shared state. I
assume that it's not much important to report total number of failures vs
noticing the failure and aborting.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0001-parallel-backup.patchapplication/octet-stream; name=0001-parallel-backup.patchDownload
From 8c29c68ff24413d8d01478080d9741b0b231d848 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Thu, 3 Oct 2019 23:41:55 +0500
Subject: [PATCH] parallel backup

---
 src/backend/access/transam/xlog.c             |    2 +-
 src/backend/replication/basebackup.c          | 1078 +++++++++++++----
 src/backend/replication/repl_gram.y           |   58 +
 src/backend/replication/repl_scanner.l        |    5 +
 src/bin/pg_basebackup/pg_basebackup.c         |  360 +++++-
 .../t/040_pg_basebackup_parallel.pl           |  571 +++++++++
 src/include/nodes/replnodes.h                 |    9 +
 src/include/replication/basebackup.h          |    2 +-
 8 files changed, 1797 insertions(+), 288 deletions(-)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 790e2c8714..3dc2ebd7dc 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10477,7 +10477,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 			ti->oid = pstrdup(de->d_name);
 			ti->path = pstrdup(buflinkpath.data);
 			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+			ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 			if (tablespaces)
 				*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index d0f210de8c..fe906dbfdf 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -52,11 +52,31 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	int32		worker;
 } basebackup_options;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	bool		isdir;
+	int32		size;
+}			pathinfo;
+
+#define STORE_PATHINFO(_filenames, _path, _isdir, _size) \
+	do { \
+		if (files != NULL) { \
+			pathinfo *pi = palloc0(sizeof(pathinfo)); \
+			strlcpy(pi->path, _path, sizeof(pi->path)); \
+			pi->isdir = _isdir; \
+			pi->size = _size; \
+			*_filenames = lappend(*_filenames, pi); \
+		} \
+	} while(0)
 
 static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
 					 List *tablespaces, bool sendtblspclinks);
+static int64 sendDir_(const char *path, int basepathlen, bool sizeonly,
+					  List *tablespaces, bool sendtblspclinks, List **files);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -71,15 +91,26 @@ static void perform_base_backup(basebackup_options *opt);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
+static int	compareFileSize(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendBackupFileList(basebackup_options *opt, List *tablespaces);
+static void SendFilesContents(basebackup_options *opt, List *filenames, bool missing_ok);
+static void include_wal_files(XLogRecPtr endptr, TimeLineID endtli);
+static void setup_throttle(int maxrate);
+static char *readfile(const char *readfilename, bool missing_ok);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
 /* Relative path of temporary statistics directory */
 static char *statrelpath = NULL;
 
+#define BACKUP_LABEL_FILE_TMP BACKUP_LABEL_FILE ".tmp"
+#define TABLESPACE_MAP_TMP TABLESPACE_MAP ".tmp"
 /*
  * Size of each block sent into the tar stream for larger files.
  */
@@ -192,6 +223,14 @@ static const char *const excludeFiles[] =
 	BACKUP_LABEL_FILE,
 	TABLESPACE_MAP,
 
+	/*
+	 * Skip backup_label.tmp or tablespace_map.tmp files. These are temporary
+	 * and are injected into the backup by SendFilesList and
+	 * SendFilesContents, will be removed after as well.
+	 */
+	BACKUP_LABEL_FILE_TMP,
+	TABLESPACE_MAP_TMP,
+
 	"postmaster.pid",
 	"postmaster.opts",
 
@@ -294,28 +333,7 @@ perform_base_backup(basebackup_options *opt)
 		SendBackupHeader(tablespaces);
 
 		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
-
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		setup_throttle(opt->maxrate);
 
 		/* Send off our tablespaces one by one */
 		foreach(lc, tablespaces)
@@ -357,7 +375,7 @@ perform_base_backup(basebackup_options *opt)
 				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 			}
 			else
-				sendTablespace(ti->path, false);
+				sendTablespace(ti->path, false, NULL);
 
 			/*
 			 * If we're including WAL, and this is the main data directory we
@@ -384,227 +402,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr, endtli);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -637,6 +435,24 @@ compareWalFileNames(const ListCell *a, const ListCell *b)
 	return strcmp(fna + 8, fnb + 8);
 }
 
+/*
+ * list_sort comparison function, to compare size attribute of pathinfo
+ * in descending order.
+ */
+static int
+compareFileSize(const ListCell *a, const ListCell *b)
+{
+	pathinfo   *fna = (pathinfo *) lfirst(a);
+	pathinfo   *fnb = (pathinfo *) lfirst(b);
+
+	if (fna->size > fnb->size)
+		return -1;
+	if (fna->size < fnb->size)
+		return 1;
+	return 0;
+
+}
+
 /*
  * Parse the base backup options passed down by the parser
  */
@@ -652,8 +468,10 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_worker = false;
 
 	MemSet(opt, 0, sizeof(*opt));
+	opt->worker = -1;
 	foreach(lopt, options)
 	{
 		DefElem    *defel = (DefElem *) lfirst(lopt);
@@ -740,6 +558,16 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "worker") == 0)
+		{
+			if (o_worker)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			opt->worker = intVal(defel->arg);
+			o_worker = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -774,7 +602,26 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_FILES_CONTENT:
+			SendFilesContents(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -968,7 +815,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool sizeonly, List **files)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -997,11 +844,11 @@ sendTablespace(char *path, bool sizeonly)
 		return 0;
 	}
 
+	STORE_PATHINFO(files, pathbuf, true, -1);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   sizeonly);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir_(pathbuf, strlen(path), sizeonly, NIL, true, files);
 
 	return size;
 }
@@ -1019,8 +866,16 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
-		bool sendtblspclinks)
+sendDir(const char *path, int basepathlen, bool sizeonly,
+		List *tablespaces, bool sendtblspclinks)
+{
+	return sendDir_(path, basepathlen, sizeonly, tablespaces, sendtblspclinks, NULL);
+}
+
+/* Same as sendDir(), except that it also returns a list of filenames in PGDATA */
+static int64
+sendDir_(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+		 bool sendtblspclinks, List **files)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -1174,6 +1029,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				STORE_PATHINFO(files, pathbuf, true, -1);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 				excludeFound = true;
 				break;
@@ -1190,6 +1047,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			STORE_PATHINFO(files, pathbuf, true, -1);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 			continue;
 		}
@@ -1211,6 +1070,9 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									sizeonly);
 
+			STORE_PATHINFO(files, pathbuf, true, -1);
+			STORE_PATHINFO(files, "./pg_wal/archive_status", true, -1);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -1240,6 +1102,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			STORE_PATHINFO(files, pathbuf, false, statbuf.st_size);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, sizeonly);
 #else
@@ -1266,6 +1129,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									sizeonly);
+			STORE_PATHINFO(files, pathbuf, true, -1);
+
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1296,13 +1161,15 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir_(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks, files);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			STORE_PATHINFO(files, pathbuf, false, statbuf.st_size);
+
+			if (!sizeonly && files == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1743,3 +1610,710 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * In parallel mode, pg_stop_backup() is not called, nor are the files sent
+ * right away. Upon receiving the BASE_BACKUP call, it sends out a list of
+ * files in $PGDATA.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, *all* functionality between do_pg_start_backup() and the end of
+	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 */
+
+	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	{
+		tablespaceinfo *ti;
+		FILE	   *fp;
+
+		SendXlogRecPtrResult(startptr, starttli);
+
+		/*
+		 * Calculate the relative path of temporary statistics directory in
+		 * order to skip the files which are located in that directory later.
+		 */
+		if (is_absolute_path(pgstat_stat_directory) &&
+			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory);
+		else
+			statrelpath = pgstat_stat_directory;
+
+		/* Add a node for the base directory at the end */
+		ti = palloc0(sizeof(tablespaceinfo));
+		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+		tablespaces = lappend(tablespaces, ti);
+
+		/* Send tablespace header */
+		SendBackupHeader(tablespaces);
+
+		/* Setup and activate network throttling, if client requested it */
+		setup_throttle(opt->maxrate);
+
+		/*
+		 * backup_label and tablespace_map are stored into temp files for
+		 * their usage are a later stage i.e. during STOP_BACKUP or while
+		 * transfering files to the client.
+		 */
+		fp = AllocateFile(BACKUP_LABEL_FILE_TMP, "w");
+		if (!fp)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not create file \"%s\": %m",
+							BACKUP_LABEL_FILE_TMP)));
+		if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
+			fflush(fp) != 0 ||
+			pg_fsync(fileno(fp)) != 0 ||
+			ferror(fp) ||
+			FreeFile(fp))
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not write file \"%s\": %m",
+							BACKUP_LABEL_FILE_TMP)));
+
+		if (opt->sendtblspcmapfile && tblspc_map_file->len > 0)
+		{
+			fp = AllocateFile(TABLESPACE_MAP_TMP, "w");
+			if (!fp)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not create file \"%s\": %m",
+								TABLESPACE_MAP_TMP)));
+			if (fwrite(tblspc_map_file->data, tblspc_map_file->len, 1, fp) != 1 ||
+				fflush(fp) != 0 ||
+				pg_fsync(fileno(fp)) != 0 ||
+				ferror(fp) ||
+				FreeFile(fp))
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not write file \"%s\": %m",
+								TABLESPACE_MAP_TMP)));
+		}
+
+		/* send out the list of file in $PGDATA */
+		SendBackupFileList(opt, tablespaces);
+	}
+	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+}
+
+/*
+ * StopBackup() - ends a parallel backup
+ *
+ * The function is called in parallel mode. It ends a parallel backup session
+ * established by 'BASE_BACKUP PARALLEL' command.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/* read backup_label file into buffer, we need it for do_pg_stop_backup */
+	labelfile = readfile(BACKUP_LABEL_FILE_TMP, false);
+
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	/* stop backup */
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	if (opt->includewal)
+		include_wal_files(endptr, endtli);
+
+	pq_putemptymessage('c');	/* CopyDone */
+	SendXlogRecPtrResult(endptr, endtli);
+
+	unlink(BACKUP_LABEL_FILE_TMP);
+	unlink(TABLESPACE_MAP_TMP);
+}
+
+/*
+ * SendBackupFileList() - sends a list of filenames of PGDATA
+ *
+ * The function collects a list of filenames, nessery for a full backup and sends
+ * this list to the client.
+ */
+static void
+SendBackupFileList(basebackup_options *opt, List *tablespaces)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+
+	foreach(lc, tablespaces)
+	{
+		List	   *filenames = NULL;
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+
+		if (ti->path == NULL)
+			sendDir_(".", 1, false, NIL, !opt->sendtblspcmapfile, &filenames);
+		else
+			sendTablespace(ti->path, false, &filenames);
+
+		/* sort the files in desending order, based on file size */
+		list_sort(filenames, compareFileSize);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 3);	/* 1 field */
+
+		/* First field - file path */
+		pq_sendstring(&buf, "path");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "isdir");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, BOOLOID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, filenames)
+		{
+			pathinfo   *pi = (pathinfo *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 3);	/* number of columns */
+
+			/* send file name */
+			len = strlen(pi->path);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, pi->path, len);
+
+			/* send isdir */
+			pq_sendint32(&buf, 1);
+			pq_sendbytes(&buf, pi->isdir ? "t" : "f", 1);
+
+			/* send size */
+			send_int8_string(&buf, pi->size);
+
+			pq_endmessage(&buf);
+		}
+
+		pfree(filenames);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendFilesContents() - sends the actual files to the caller
+ *
+ * The function sends the files over to the caller using the COPY protocol.
+ */
+static void
+SendFilesContents(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	char	   *labelfile;
+	ListCell   *lc;
+	char		startxlogfilename[MAXFNAMELEN];
+	bool		basetablespace = true;
+	int			basepathlen = 1;
+	char		ch;
+	uint32		hi,
+				lo;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/*
+	 * LABEL is reused here to identify the tablespace path on server. Its empty
+	 * in case of 'base' tablespace.
+	 */
+	if (is_absolute_path(opt->label))
+	{
+		basepathlen = strlen(opt->label);
+		basetablespace = false;
+	}
+
+	/* retrive the backup start location from backup_label file. */
+	labelfile = readfile(BACKUP_LABEL_FILE_TMP, false);
+	if (sscanf(labelfile, "START WAL LOCATION: %X/%X (file %24s)%c",
+			   &hi, &lo, startxlogfilename,
+			   &ch) != 4 || ch != '\n')
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE_TMP)));
+	startptr = ((uint64) hi) << 32 | lo;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	if (opt->worker == 0 && basetablespace) /* 'base' tablespace */
+	{
+		/* Send BACKUP_LABEL_FILE file */
+		sendFileWithContent(BACKUP_LABEL_FILE, labelfile);
+
+		/* Send TABLESPACE_MAP file */
+		if (opt->sendtblspcmapfile)
+		{
+			char	   *mapfile = readfile(TABLESPACE_MAP_TMP, true);
+
+			if (mapfile)
+			{
+				sendFileWithContent(TABLESPACE_MAP, mapfile);
+				pfree(mapfile);
+			}
+		}
+	}
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/* Allow symbolic links in pg_tblspc only */
+		if (strstr(pathbuf, "./pg_tblspc") != NULL &&
+#ifndef WIN32
+			S_ISLNK(statbuf.st_mode)
+#else
+			pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			char		linkpath[MAXPGPATH];
+			int			rllen;
+
+			rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not read symbolic link \"%s\": %m",
+								pathbuf)));
+			if (rllen >= sizeof(linkpath))
+				ereport(ERROR,
+						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+						 errmsg("symbolic link \"%s\" target is too long",
+								pathbuf)));
+			linkpath[rllen] = '\0';
+
+			_tarWriteHeader(pathbuf, linkpath, &statbuf, false);
+		}
+		else if (S_ISDIR(statbuf.st_mode))
+		{
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else if (
+#ifndef WIN32
+				 S_ISLNK(statbuf.st_mode)
+#else
+				 pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			/*
+			 * If symlink, write it as a directory. file symlinks only allowed
+			 * in pg_tblspc
+			 */
+			statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report totoal checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+static void
+include_wal_files(XLogRecPtr endptr, TimeLineID endtli)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the required
+	 * WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and include
+	 * all WAL files in the range between 'startptr' and 'endptr', regardless
+	 * of the timeline the file is stamped with. If there are some spurious
+	 * WAL files belonging to timelines that don't belong in this server's
+	 * history, they will be included too. Normally there shouldn't be such
+	 * files, but if there are, there's little harm in including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we need
+	 * were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from oldest
+	 * to newest, to reduce the chance that a file is recycled before we get a
+	 * chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since we
+	 * are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again after
+		 * promotion of a new node. This is in line with walreceiver.c always
+		 * doing an XLogArchiveForceDone() after a complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history file
+	 * is required for recovery, and even that only if there happens to be a
+	 * timeline switch in the first WAL segment that contains the checkpoint
+	 * record, or if we're taking a base backup from a standby server and the
+	 * target timeline changes while the backup is taken. But they are small
+	 * and highly useful for debugging purposes, so better include them all,
+	 * always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	/* Setup and activate network throttling, if client requested it */
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
+
+static char *
+readfile(const char *readfilename, bool missing_ok)
+{
+	struct stat statbuf;
+	FILE	   *fp;
+	char	   *data;
+	int			r;
+
+	if (stat(readfilename, &statbuf))
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						readfilename)));
+	}
+
+	fp = AllocateFile(readfilename, "r");
+	if (!fp)
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not open file \"%s\": %m", readfilename)));
+	}
+
+	data = palloc(statbuf.st_size + 1);
+	r = fread(data, statbuf.st_size, 1, fp);
+	data[statbuf.st_size] = '\0';
+
+	/* Close the file */
+	if (r != 1 || ferror(fp) || FreeFile(fp))
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not read file \"%s\": %m",
+						readfilename)));
+
+	return data;
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..88e384bf3c 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,6 +87,10 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_FILES_CONTENT
+%token K_STOP_BACKUP
+%token K_WORKER
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
@@ -102,6 +106,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -162,6 +168,29 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_START_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILES_CONTENT backup_files base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_FILES_CONTENT;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
@@ -214,6 +243,35 @@ base_backup_opt:
 				  $$ = makeDefElem("noverify_checksums",
 								   (Node *)makeInteger(true), -1);
 				}
+			| K_WORKER UCONST
+				{
+				  $$ = makeDefElem("worker",
+								   (Node *)makeInteger($2), -1);
+				}
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{
+					$$ = $2;
+				}
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
+				{
+					$$ = list_make1($1);
+				}
+			| backup_files_list ',' backup_file
+				{
+					$$ = lappend($1, $3);
+				}
+			;
+
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..4836828c39 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,11 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_FILES_CONTENT	{ return K_SEND_FILES_CONTENT; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+WORKER				{ return K_WORKER; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 55ef13926d..5139dcbe03 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -41,6 +41,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -57,6 +58,15 @@ typedef struct TablespaceList
 	TablespaceListCell *tail;
 } TablespaceList;
 
+typedef struct WorkerFiles
+{
+	int			num_files;
+	char	   *tspath;
+	SimpleStringList *worker_files;
+
+}			WorkerFiles;
+
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -110,6 +120,10 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+static SimpleOidList workerspid = {NULL, NULL};
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -141,7 +155,7 @@ static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
 
-static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
+static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum, int worker);
 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
 
@@ -151,6 +165,10 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupEnd(void);
+static int	ReceiveFiles(WorkerFiles * workerFiles, int worker);
+static void create_workers_and_fetch(WorkerFiles * workerFiles);
+static int	simple_list_length(SimpleStringList *list);
 
 static void
 cleanup_directories_atexit(void)
@@ -349,6 +367,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -921,7 +940,7 @@ writeTarData(
  * No attempt to inspect or validate the contents of the file is done.
  */
 static void
-ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
+ReceiveTarFile(PGconn *conn, PGresult *res, int rownum, int worker)
 {
 	char		filename[MAXPGPATH];
 	char	   *copybuf = NULL;
@@ -978,7 +997,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 #ifdef HAVE_LIBZ
 			if (compresslevel != 0)
 			{
-				snprintf(filename, sizeof(filename), "%s/base.tar.gz", basedir);
+				if (numWorkers > 1)
+					snprintf(filename, sizeof(filename), "%s/base.%d.tar.gz", basedir, worker);
+				else
+					snprintf(filename, sizeof(filename), "%s/base.tar.gz", basedir);
 				ztarfile = gzopen(filename, "wb");
 				if (gzsetparams(ztarfile, compresslevel,
 								Z_DEFAULT_STRATEGY) != Z_OK)
@@ -991,7 +1013,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			else
 #endif
 			{
-				snprintf(filename, sizeof(filename), "%s/base.tar", basedir);
+				if (numWorkers > 1)
+					snprintf(filename, sizeof(filename), "%s/base.%d.tar", basedir, worker);
+				else
+					snprintf(filename, sizeof(filename), "%s/base.tar", basedir);
 				tarfile = fopen(filename, "wb");
 			}
 		}
@@ -1004,8 +1029,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 #ifdef HAVE_LIBZ
 		if (compresslevel != 0)
 		{
-			snprintf(filename, sizeof(filename), "%s/%s.tar.gz", basedir,
-					 PQgetvalue(res, rownum, 0));
+			if (numWorkers > 1)
+				snprintf(filename, sizeof(filename), "%s/%s.%d.tar.gz", basedir,
+						 PQgetvalue(res, rownum, 0), worker);
+			else
+				snprintf(filename, sizeof(filename), "%s/%s.tar.gz", basedir,
+						 PQgetvalue(res, rownum, 0));
 			ztarfile = gzopen(filename, "wb");
 			if (gzsetparams(ztarfile, compresslevel,
 							Z_DEFAULT_STRATEGY) != Z_OK)
@@ -1018,8 +1047,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		else
 #endif
 		{
-			snprintf(filename, sizeof(filename), "%s/%s.tar", basedir,
-					 PQgetvalue(res, rownum, 0));
+			if (numWorkers > 1)
+				snprintf(filename, sizeof(filename), "%s/%s.%d.tar", basedir,
+						 PQgetvalue(res, rownum, 0), worker);
+			else
+				snprintf(filename, sizeof(filename), "%s/%s.tar", basedir,
+						 PQgetvalue(res, rownum, 0));
 			tarfile = fopen(filename, "wb");
 		}
 	}
@@ -1475,6 +1508,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 			 */
 			snprintf(filename, sizeof(filename), "%s/%s", current_path,
 					 copybuf);
+
 			if (filename[strlen(filename) - 1] == '/')
 			{
 				/*
@@ -1486,21 +1520,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * Directory
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
+
+					/*
+					 * In parallel mode, we create directories before fetching
+					 * files so its Ok if a directory already exist.
+					 */
 					if (mkdir(filename, pg_dir_create_mode) != 0)
 					{
-						/*
-						 * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
-						 * clusters) will have been created by the wal
-						 * receiver process. Also, when the WAL directory
-						 * location was specified, pg_wal (or pg_xlog) has
-						 * already been created as a symbolic link before
-						 * starting the actual backup. So just ignore creation
-						 * failures on related directories.
-						 */
-						if (!((pg_str_endswith(filename, "/pg_wal") ||
-							   pg_str_endswith(filename, "/pg_xlog") ||
-							   pg_str_endswith(filename, "/archive_status")) &&
-							  errno == EEXIST))
+						if (errno != EEXIST)
 						{
 							pg_log_error("could not create directory \"%s\": %m",
 										 filename);
@@ -1528,8 +1555,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * can map them too.)
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
-
 					mapped_tblspc_path = get_tablespace_mapping(&copybuf[157]);
+
 					if (symlink(mapped_tblspc_path, filename) != 0)
 					{
 						pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
@@ -1716,7 +1743,8 @@ BaseBackup(void)
 	}
 
 	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+		psprintf("%s LABEL '%s' %s %s %s %s %s %s %s",
+				 (numWorkers > 1) ? "START_BACKUP" : "BASE_BACKUP",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
 				 includewal == FETCH_WAL ? "WAL" : "",
@@ -1830,20 +1858,102 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		WorkerFiles *workerFiles = palloc0(sizeof(WorkerFiles) * tablespacecount);
+
+		tablespacehdr = res;
+
+		for (i = 0; i < tablespacecount; i++)
+		{
+			bool		basetablespace;
+
+			workerFiles[i].worker_files = palloc0(sizeof(SimpleStringList) * numWorkers);
+
+			/*
+			 * Get the header
+			 */
+			res = PQgetResult(conn);
+			if (PQresultStatus(res) != PGRES_TUPLES_OK)
+			{
+				pg_log_error("could not get backup header: %s",
+							 PQerrorMessage(conn));
+				exit(1);
+			}
+			if (PQntuples(res) < 1)
+			{
+				pg_log_error("no data returned from server");
+				exit(1);
+			}
+
+			basetablespace = PQgetisnull(tablespacehdr, i, 0);
+			workerFiles[i].tspath = PQgetvalue(tablespacehdr, i, 1);
+			workerFiles[i].num_files = 0;
+
+			for (int j = 0; j < PQntuples(res); j++)
+			{
+				const char *path = PQgetvalue(res, j, 0);
+				bool		isdir = PQgetvalue(res, j, 1)[0] == 't';
+
+				if (format == 'p' && isdir)
+				{
+					char		dirpath[MAXPGPATH];
+
+					if (basetablespace)
+						snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, path);
+					else
+					{
+						const char *tspath = PQgetvalue(tablespacehdr, i, 1);
+
+						snprintf(dirpath, sizeof(dirpath), "%s/%s",
+								 get_tablespace_mapping(tspath), (path + strlen(tspath) + 1));
+					}
+
+					if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+					{
+						if (errno != EEXIST)
+						{
+							pg_log_error("could not create directory \"%s\": %m",
+										 dirpath);
+							exit(1);
+						}
+					}
+				}
+
+				workerFiles[i].num_files++;
+				simple_string_list_append(&workerFiles[i].worker_files[j % numWorkers], path);
+			}
+			PQclear(res);
+		}
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data: %s", PQerrorMessage(conn));
+			exit(1);
+		}
+
+		res = PQgetResult(conn);
+		create_workers_and_fetch(workerFiles);
+		ParallelBackupEnd();
+	}
+	else
+	{
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i, 0);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+	}
 
 	if (showprogress)
 	{
-		progress_report(PQntuples(res), NULL, true);
+		progress_report(PQntuples(tablespacehdr), NULL, true);
 		if (isatty(fileno(stderr)))
 			fprintf(stderr, "\n");	/* Need to move to next line */
 	}
@@ -2043,6 +2153,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2070,7 +2181,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2211,6 +2322,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2325,6 +2439,14 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2397,3 +2519,173 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+static void
+ParallelBackupEnd(void)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP %s %s",
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	if (format == 't')
+		ReceiveTarFile(conn, res, tablespacecount, numWorkers);
+	else
+		ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+
+	PQclear(res);
+}
+
+static int
+ReceiveFiles(WorkerFiles * workerFiles, int worker)
+{
+	SimpleStringListCell *cell;
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn;
+	int			i;
+
+	worker_conn = GetConnection();
+	for (i = 0; i < tablespacecount; i++)
+	{
+		SimpleStringList *files = &workerFiles[i].worker_files[worker];
+		PQExpBuffer buf = createPQExpBuffer();
+
+		if (simple_list_length(files) <= 0)
+			continue;
+
+
+		/*
+		 * build query in form of: SEND_FILES_CONTENT ('base/1/1245/32683',
+		 * 'base/1/1245/32683', ...) [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_FILES_CONTENT (");
+		for (cell = files->head; cell; cell = cell->next)
+		{
+			if (cell != files->tail)
+				appendPQExpBuffer(buf, "'%s' ,", cell->val);
+			else
+				appendPQExpBuffer(buf, "'%s'", cell->val);
+		}
+		appendPQExpBufferStr(buf, " )");
+
+		/*
+		 * Add backup options to the command. we are reusing the LABEL here to
+		 * keep the original tablespace path on the server.
+		 */
+		appendPQExpBuffer(buf, " LABEL '%s' WORKER %u %s %s",
+						  workerFiles[i].tspath,
+						  worker,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+		destroyPQExpBuffer(buf);
+
+		if (format == 't')
+			ReceiveTarFile(worker_conn, tablespacehdr, i, worker);
+		else
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, i);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	PQfinish(worker_conn);
+
+	return 0;
+}
+
+static void
+create_workers_and_fetch(WorkerFiles * workerFiles)
+{
+	int			status;
+	int			pid,
+				i;
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		pid = fork();
+		if (pid == 0)
+		{
+			/* in child process */
+			_exit(ReceiveFiles(workerFiles, i));
+		}
+		else if (pid < 0)
+		{
+			pg_log_error("could not create backup worker: %m");
+			exit(1);
+		}
+
+		simple_oid_list_append(&workerspid, pid);
+		if (verbose)
+			pg_log_info("backup worker (%d) created", pid);
+
+		/*
+		 * Else we are in the parent process and all is well.
+		 */
+	}
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		pid = waitpid(-1, &status, 0);
+
+		if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_FAILURE)
+		{
+			SimpleOidListCell *cell;
+
+			pg_log_error("backup worker (%d) failed with code %d", pid, WEXITSTATUS(status));
+
+			/* error. kill other workers and exit. */
+			for (cell = workerspid.head; cell; cell = cell->next)
+			{
+				if (pid != cell->val)
+				{
+					kill(cell->val, SIGTERM);
+					pg_log_error("backup worker killed %d", cell->val);
+				}
+			}
+
+			exit(1);
+		}
+	}
+}
+
+
+static int
+simple_list_length(SimpleStringList *list)
+{
+	int			len = 0;
+	SimpleStringListCell *cell;
+
+	for (cell = list->head; cell; cell = cell->next, len++)
+		;
+
+	return len;
+}
diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..6c31214f3d
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,571 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 106;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+foreach my $filename (
+	qw(base.0.tar base.1.tar base.2.tar base.3.tar))
+{
+	ok(!-f "$tempdir/backup/$filename", "backup $filename tar created");
+}
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# Tar format doesn't support filenames longer than 100 bytes.
+my $superlongname = "superlongname_" . ("x" x 100);
+my $superlongpath = "$pgdata/$superlongname";
+
+open my $file, '>', "$superlongpath"
+  or die "unable to create file $superlongpath";
+close $file;
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft', "-j 4" ],
+	'pg_basebackup tar with long name fails');
+unlink "$pgdata/$superlongname";
+
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+	# Create a temporary directory in the system location and symlink it
+	# to our physical temp location.  That way we can use shorter names
+	# for the tablespace directories, which hopefully won't run afoul of
+	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup2", '-Ft', "-j 4" ],
+		'tar format with tablespaces');
+	ok(-f "$tempdir/tarbackup2/base.0.tar", 'backup tar was created');
+	my @tblspc_tars = glob "$tempdir/tarbackup2/[0-9]*.tar";
+	is(scalar(@tblspc_tars), 3, 'one tablespace tar was created');
+	rmtree("$tempdir/tarbackup2");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+
+	mkdir "$tempdir/$superlongname";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc3 LOCATION '$tempdir/$superlongname';");
+	$node->command_ok(
+		[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l3", '-Ft' , '-j 4'],
+		'pg_basebackup tar with long symlink target');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc3;");
+	rmtree("$tempdir/tarbackup_l3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxst", '-X', 'stream', '-Ft' , "-j 4"],
+	'pg_basebackup -X stream runs in tar mode');
+ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created");
+rmtree("$tempdir/backupxst");
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+#$node->command_checks_all(
+#	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt3", '-j 4'],
+#	1,
+#	[qr{^$}],
+#	[qr/^WARNING.*checksum verification failed/s],
+#	'pg_basebackup correctly report the total number of checksum mismatches');
+#rmtree("$tempdir/backup_corrupt3");
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..f92d593e2e 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,13 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_FILES_CONTENT,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +49,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..9e792af99d 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool sizeonly, List **files);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122)

#14Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#13)
Re: WIP/PoC for parallel backup

On Fri, Oct 4, 2019 at 7:02 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

Based on my understanding your main concern is that the files won't be distributed fairly i.e one worker might get a big file and take more time while others get done early with smaller files? In this approach I have created a list of files in descending order based on there sizes so all the big size files will come at the top. The maximum file size in PG is 1GB so if we have four workers who are picking up file from the list one by one, the worst case scenario is that one worker gets a file of 1GB to process while others get files of smaller size. However with this approach of descending files based on size and handing it out to workers one by one, there is a very high likelihood of workers getting work evenly. does this address your concerns?

Somewhat, but I'm not sure it's good enough. There are lots of reasons
why two processes that are started at the same time with the same
amount of work might not finish at the same time.

I'm also not particularly excited about having the server do the
sorting based on file size. Seems like that ought to be the client's
job, if the client needs the sorting.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#15Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Asif Rehman (#13)
Re: WIP/PoC for parallel backup

Thanks Asif for the patch. I am opting this for a review. Patch is
bit big, so here are very initial comments to make the review process
easier.

1) Patch seems doing lot of code shuffling, I think it would be easy
to review if you can break the clean up patch separately.

Example:
a: setup_throttle
b: include_wal_files

2) As I can see this patch basically have three major phase.

a) Introducing new commands like START_BACKUP, SEND_FILES_CONTENT and
STOP_BACKUP.
b) Implementation of actual parallel backup.
c) Testcase

I would suggest, if you can break out in three as a separate patch that
would be nice. It will benefit in reviewing the patch.

3) In your patch you are preparing the backup manifest (file which
giving the information about the data files). Robert Haas, submitted
the backup manifests patch on another thread [1]/messages/by-id/CA+TgmoZV8dw1H2bzZ9xkKwdrk8+XYa+DC9H=F7heO2zna5T6qg@mail.gmail.com, and I think we
should use that patch to get the backup manifests for parallel backup.

Further, I will continue to review patch but meanwhile if you can
break the patches - so that review process be easier.

[1]: /messages/by-id/CA+TgmoZV8dw1H2bzZ9xkKwdrk8+XYa+DC9H=F7heO2zna5T6qg@mail.gmail.com
/messages/by-id/CA+TgmoZV8dw1H2bzZ9xkKwdrk8+XYa+DC9H=F7heO2zna5T6qg@mail.gmail.com

Thanks,

On Fri, Oct 4, 2019 at 4:32 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Thu, Oct 3, 2019 at 6:40 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Sep 27, 2019 at 12:00 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

- SEND_FILES_CONTENTS (file1, file2,...) - returns the files in

given list.

pg_basebackup will then send back a list of filenames in this

command. This commands will be send by each worker and that worker will be
getting the said files.

Seems reasonable, but I think you should just pass one file name and
use the command multiple times, once per file.

I considered this approach initially, however, I adopted the current

strategy to avoid multiple round trips between the server and clients and
save on query processing time by issuing a single command rather than
multiple ones. Further fetching multiple files at once will also aid in
supporting the tar format by utilising the existing ReceiveTarFile()
function and will be able to create a tarball for per tablespace per worker.

I think that sending multiple filenames on a line could save some time
when there are lots of very small files, because then the round-trip
overhead could be significant.

However, if you've got mostly big files, I think this is going to be a
loser. It'll be fine if you're able to divide the work exactly evenly,
but that's pretty hard to do, because some workers may succeed in
copying the data faster than others for a variety of reasons: some
data is in memory, some data has to be read from disk, different data
may need to be read from different disks that run at different speeds,
not all the network connections may run at the same speed. Remember
that the backup's not done until the last worker finishes, and so
there may well be a significant advantage in terms of overall speed in
putting some energy into making sure that they finish as close to each
other in time as possible.

To put that another way, the first time all the workers except one get
done while the last one still has 10GB of data to copy, somebody's
going to be unhappy.

I have updated the patch (see the attached patch) to include tablespace
support, tar format support and all other backup base backup options to
work in parallel mode as well. As previously suggested, I have removed
BASE_BACKUP [PARALLEL] and have added START_BACKUP instead to start the
backup. The tar format will write multiple tar files depending upon the
number of workers specified. Also made all commands
(START_BACKUP/SEND_FILES_CONTENT/STOP_BACKUP) to accept the
base_backup_opt_list. This way the command-line options can also be
provided to these commands. Since the command-line options don't change
once the backup initiates, I went this way instead of storing them in
shared state.

The START_BACKUP command will now return a sorted list of files in
descending order based on file sizes. This way, the larger files will be on
top of the list. hence these files will be assigned to workers one by one,
making it so that the larger files will be copied before other files.

Based on my understanding your main concern is that the files won't be
distributed fairly i.e one worker might get a big file and take more time
while others get done early with smaller files? In this approach I have
created a list of files in descending order based on there sizes so all the
big size files will come at the top. The maximum file size in PG is 1GB so
if we have four workers who are picking up file from the list one by one,
the worst case scenario is that one worker gets a file of 1GB to process
while others get files of smaller size. However with this approach of
descending files based on size and handing it out to workers one by one,
there is a very high likelihood of workers getting work evenly. does this
address your concerns?

Furthermore the patch also includes the regression test. As t/
010_pg_basebackup.pl test-case is testing base backup comprehensively, so
I have duplicated it to "t/040_pg_basebackup_parallel.pl" and added
parallel option in all of its tests, to make sure parallel mode works
expectantly. The one thing that differs from base backup is the file
checksum reporting. In parallel mode, the total number of checksum failures
are not reported correctly however it will abort the backup whenever a
checksum failure occurs. This is because processes are not maintaining any
shared state. I assume that it's not much important to report total number
of failures vs noticing the failure and aborting.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Rushabh Lathia

#16Asif Rehman
asifr.rehman@gmail.com
In reply to: Rushabh Lathia (#15)
Re: WIP/PoC for parallel backup

On Mon, Oct 7, 2019 at 1:52 PM Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

Thanks Asif for the patch. I am opting this for a review. Patch is
bit big, so here are very initial comments to make the review process
easier.

Thanks Rushabh for reviewing the patch.

1) Patch seems doing lot of code shuffling, I think it would be easy
to review if you can break the clean up patch separately.

Example:
a: setup_throttle
b: include_wal_files

2) As I can see this patch basically have three major phase.

a) Introducing new commands like START_BACKUP, SEND_FILES_CONTENT and
STOP_BACKUP.
b) Implementation of actual parallel backup.
c) Testcase

I would suggest, if you can break out in three as a separate patch that
would be nice. It will benefit in reviewing the patch.

Sure, why not. I will break them into multiple patches.

3) In your patch you are preparing the backup manifest (file which
giving the information about the data files). Robert Haas, submitted
the backup manifests patch on another thread [1], and I think we
should use that patch to get the backup manifests for parallel backup.

Sure. Though the backup manifest patch calculates and includes the checksum
of backup files and is done
while the file is being transferred to the frontend-end. The manifest file
itself is copied at the
very end of the backup. In parallel backup, I need the list of filenames
before file contents are transferred, in
order to divide them into multiple workers. For that, the manifest file has
to be available when START_BACKUP
is called.

That means, backup manifest should support its creation while excluding the
checksum during START_BACKUP().
I also need the directory information as well for two reasons:

- In plain format, base path has to exist before we can write the file. we
can extract the base path from the file
but doing that for all files does not seem a good idea.
- base backup does not include the content of some directories but those
directories although empty, are still
expected in PGDATA.

I can make these changes part of parallel backup (which would be on top of
backup manifest patch) or
these changes can be done as part of manifest patch and then parallel can
use them.

Robert what do you suggest?

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#17Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#16)
Re: WIP/PoC for parallel backup

On Mon, Oct 7, 2019 at 8:48 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

Sure. Though the backup manifest patch calculates and includes the checksum of backup files and is done
while the file is being transferred to the frontend-end. The manifest file itself is copied at the
very end of the backup. In parallel backup, I need the list of filenames before file contents are transferred, in
order to divide them into multiple workers. For that, the manifest file has to be available when START_BACKUP
is called.

That means, backup manifest should support its creation while excluding the checksum during START_BACKUP().
I also need the directory information as well for two reasons:

- In plain format, base path has to exist before we can write the file. we can extract the base path from the file
but doing that for all files does not seem a good idea.
- base backup does not include the content of some directories but those directories although empty, are still
expected in PGDATA.

I can make these changes part of parallel backup (which would be on top of backup manifest patch) or
these changes can be done as part of manifest patch and then parallel can use them.

Robert what do you suggest?

I think we should probably not use backup manifests here, actually. I
initially thought that would be a good idea, but after further thought
it seems like it just complicates the code to no real benefit. I
suggest that the START_BACKUP command just return a result set, like a
query, with perhaps four columns: file name, file type ('d' for
directory or 'f' for file), file size, file mtime. pg_basebackup will
ignore the mtime, but some other tools might find that useful
information.

I wonder if we should also split START_BACKUP (which should enter
non-exclusive backup mode) from GET_FILE_LIST, in case some other
client program wants to use one of those but not the other. I think
that's probably a good idea, but not sure.

I still think that the files should be requested one at a time, not a
huge long list in a single command.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#18Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#17)
Re: WIP/PoC for parallel backup

On Mon, Oct 7, 2019 at 6:05 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Oct 7, 2019 at 8:48 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

Sure. Though the backup manifest patch calculates and includes the

checksum of backup files and is done

while the file is being transferred to the frontend-end. The manifest

file itself is copied at the

very end of the backup. In parallel backup, I need the list of filenames

before file contents are transferred, in

order to divide them into multiple workers. For that, the manifest file

has to be available when START_BACKUP

is called.

That means, backup manifest should support its creation while excluding

the checksum during START_BACKUP().

I also need the directory information as well for two reasons:

- In plain format, base path has to exist before we can write the file.

we can extract the base path from the file

but doing that for all files does not seem a good idea.
- base backup does not include the content of some directories but those

directories although empty, are still

expected in PGDATA.

I can make these changes part of parallel backup (which would be on top

of backup manifest patch) or

these changes can be done as part of manifest patch and then parallel

can use them.

Robert what do you suggest?

I think we should probably not use backup manifests here, actually. I
initially thought that would be a good idea, but after further thought
it seems like it just complicates the code to no real benefit.

Okay.

I
suggest that the START_BACKUP command just return a result set, like a
query, with perhaps four columns: file name, file type ('d' for
directory or 'f' for file), file size, file mtime. pg_basebackup will
ignore the mtime, but some other tools might find that useful
information.

yes current patch already returns the result set. will add the additional
information.

I wonder if we should also split START_BACKUP (which should enter
non-exclusive backup mode) from GET_FILE_LIST, in case some other
client program wants to use one of those but not the other. I think
that's probably a good idea, but not sure.

Currently pg_basebackup does not enter in exclusive backup mode and other
tools have to
use pg_start_backup() and pg_stop_backup() functions to achieve that. Since
we are breaking
backup into multiple command, I believe it would be a good idea to have
this option. I will include
it in next revision of this patch.

I still think that the files should be requested one at a time, not a
huge long list in a single command.

sure, will make the change.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#19Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Robert Haas (#17)
Re: WIP/PoC for parallel backup

On Mon, Oct 7, 2019 at 6:06 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Oct 7, 2019 at 8:48 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

Sure. Though the backup manifest patch calculates and includes the

checksum of backup files and is done

while the file is being transferred to the frontend-end. The manifest

file itself is copied at the

very end of the backup. In parallel backup, I need the list of filenames

before file contents are transferred, in

order to divide them into multiple workers. For that, the manifest file

has to be available when START_BACKUP

is called.

That means, backup manifest should support its creation while excluding

the checksum during START_BACKUP().

I also need the directory information as well for two reasons:

- In plain format, base path has to exist before we can write the file.

we can extract the base path from the file

but doing that for all files does not seem a good idea.
- base backup does not include the content of some directories but those

directories although empty, are still

expected in PGDATA.

I can make these changes part of parallel backup (which would be on top

of backup manifest patch) or

these changes can be done as part of manifest patch and then parallel

can use them.

Robert what do you suggest?

I think we should probably not use backup manifests here, actually. I
initially thought that would be a good idea, but after further thought
it seems like it just complicates the code to no real benefit. I
suggest that the START_BACKUP command just return a result set, like a
query, with perhaps four columns: file name, file type ('d' for
directory or 'f' for file), file size, file mtime. pg_basebackup will
ignore the mtime, but some other tools might find that useful
information.

I wonder if we should also split START_BACKUP (which should enter
non-exclusive backup mode) from GET_FILE_LIST, in case some other
client program wants to use one of those but not the other. I think
that's probably a good idea, but not sure.

I still think that the files should be requested one at a time, not a
huge long list in a single command.

What about have an API to get the single file or list of files? We will use
a single file in
our application and other tools can get the benefit of list of files.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Ibrar Ahmed

#20Robert Haas
robertmhaas@gmail.com
In reply to: Ibrar Ahmed (#19)
Re: WIP/PoC for parallel backup

On Mon, Oct 7, 2019 at 9:43 AM Ibrar Ahmed <ibrar.ahmad@gmail.com> wrote:

What about have an API to get the single file or list of files? We will use a single file in
our application and other tools can get the benefit of list of files.

That sounds a bit speculative to me. Who is to say that anyone will
find that useful? I mean, I think it's fine and good to build the
functionality that we need in a way that maximizes the likelihood that
other tools can reuse that functionality, and I think we should do
that. But I don't think it's smart to build functionality that we
don't really need in the hope that somebody else will find it useful
unless we're pretty sure that they actually will. I don't see that as
being the case here; YMMV.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#21Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#18)
4 attachment(s)
Re: WIP/PoC for parallel backup

On Mon, Oct 7, 2019 at 6:35 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Mon, Oct 7, 2019 at 6:05 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Oct 7, 2019 at 8:48 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Sure. Though the backup manifest patch calculates and includes the

checksum of backup files and is done

while the file is being transferred to the frontend-end. The manifest

file itself is copied at the

very end of the backup. In parallel backup, I need the list of

filenames before file contents are transferred, in

order to divide them into multiple workers. For that, the manifest file

has to be available when START_BACKUP

is called.

That means, backup manifest should support its creation while excluding

the checksum during START_BACKUP().

I also need the directory information as well for two reasons:

- In plain format, base path has to exist before we can write the file.

we can extract the base path from the file

but doing that for all files does not seem a good idea.
- base backup does not include the content of some directories but

those directories although empty, are still

expected in PGDATA.

I can make these changes part of parallel backup (which would be on top

of backup manifest patch) or

these changes can be done as part of manifest patch and then parallel

can use them.

Robert what do you suggest?

I think we should probably not use backup manifests here, actually. I
initially thought that would be a good idea, but after further thought
it seems like it just complicates the code to no real benefit.

Okay.

I
suggest that the START_BACKUP command just return a result set, like a
query, with perhaps four columns: file name, file type ('d' for
directory or 'f' for file), file size, file mtime. pg_basebackup will
ignore the mtime, but some other tools might find that useful
information.

yes current patch already returns the result set. will add the additional
information.

I wonder if we should also split START_BACKUP (which should enter
non-exclusive backup mode) from GET_FILE_LIST, in case some other
client program wants to use one of those but not the other. I think
that's probably a good idea, but not sure.

Currently pg_basebackup does not enter in exclusive backup mode and other
tools have to
use pg_start_backup() and pg_stop_backup() functions to achieve that.
Since we are breaking
backup into multiple command, I believe it would be a good idea to have
this option. I will include
it in next revision of this patch.

I still think that the files should be requested one at a time, not a
huge long list in a single command.

sure, will make the change.

I have refactored the functionality into multiple smaller patches in order
to make the review process easier. I have divided the code into backend
changes and pg_basebackup changes. The
backend replication system now supports the following commands:

- START_BACKUP
- SEND_FILE_LIST
- SEND_FILES_CONTENT
- STOP_BACKUP

The START_BACKUP will not return the list of files, instead SEND_FILE_LIST
is used for that. The START_BACKUP
now calls pg_start_backup and returns starting WAL position, tablespace
header information and content of backup label file.
Initially I was using tmp files to store the backup_label content but that
turns out to be bad idea, because there can be multiple
non-exclusive backups running. The backup label information is needed by
stop_backup so pg_basebackup will send it as part
of STOP_BACKUP.

The SEND_FILE_LIST will return the list of files. It will be returned as
resultset having four columns (filename, type, size, mtime).
The SEND_FILES_CONTENT can now return the single file or multiple files as
required. There is not much change required to
support both, so I believe it will be much useable this way if other tools
want to utilise it.

As per suggestion from Robert, I am currently working on making changes in
pg_basebackup to fetch files one by one. However that's not complete and
the attach patch
is still using the old method of multi-file fetching to test the backend
commands. I will send an updated patch which will contain the changes on
fetching file one by one.

I wanted to share the backend patch to get some feedback in the mean time.

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0001-Refactor-some-basebackup-code-to-increase-reusabilit.patchapplication/octet-stream; name=0001-Refactor-some-basebackup-code-to-increase-reusabilit.patchDownload
From 2ee6bc8d60ab73f8426166ca1864a062e9a51431 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 9 Oct 2019 12:39:41 +0500
Subject: [PATCH 1/4] Refactor some basebackup code to increase reusability, in
 anticipation of adding parallel backup

---
 src/backend/access/transam/xlog.c    | 191 +++++-----
 src/backend/replication/basebackup.c | 512 ++++++++++++++-------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 372 insertions(+), 333 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0ff9af53fe..577feccea5 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10282,10 +10282,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10411,93 +10407,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
 		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collectTablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12261,3 +12172,103 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile, bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	/* Collect information about all tablespaces */
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to
+		 * ensure that we can distinguish between the newline in the
+		 * tablespace path and end of line while reading tablespace_map
+		 * file during archive recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory
+		 * when it's located within PGDATA, or NULL if it's located
+		 * elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created
+		 * them. Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index d0f210de8c..a05a97ded2 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -68,10 +68,12 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt);
+static void include_wal_files(XLogRecPtr endptr, TimeLineID endtli);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
+static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
@@ -294,28 +296,7 @@ perform_base_backup(basebackup_options *opt)
 		SendBackupHeader(tablespaces);
 
 		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
-
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		setup_throttle(opt->maxrate);
 
 		/* Send off our tablespaces one by one */
 		foreach(lc, tablespaces)
@@ -384,227 +365,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr, endtli);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -1743,3 +1504,268 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * Append the required WAL files to the backup tar file. It assumes that the
+ * last tar file is "open" and the WALs will be appended to it.
+ */
+static void
+include_wal_files(XLogRecPtr endptr, TimeLineID endtli)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the
+	 * required WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and
+	 * include all WAL files in the range between 'startptr' and 'endptr',
+	 * regardless of the timeline the file is stamped with. If there are
+	 * some spurious WAL files belonging to timelines that don't belong in
+	 * this server's history, they will be included too. Normally there
+	 * shouldn't be such files, but if there are, there's little harm in
+	 * including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we
+	 * need were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from
+	 * oldest to newest, to reduce the chance that a file is recycled
+	 * before we get a chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since
+	 * we are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		CHECK_FREAD_ERROR(fp, pathbuf);
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again
+		 * after promotion of a new node. This is in line with
+		 * walreceiver.c always doing an XLogArchiveForceDone() after a
+		 * complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history
+	 * file is required for recovery, and even that only if there happens
+	 * to be a timeline switch in the first WAL segment that contains the
+	 * checkpoint record, or if we're taking a base backup from a standby
+	 * server and the target timeline changes while the backup is taken.
+	 * But they are small and highly useful for debugging purposes, so
+	 * better include them all, always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	/* Setup and activate network throttling, if client requested it */
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d519252aad..5b0aa8ae85 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 									 bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
+extern void collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+							   bool infotbssize, bool needtblspcmapfile);
 extern void do_pg_abort_backup(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.0 (Apple Git-122)

0004-parallel-backup-testcase.patchapplication/octet-stream; name=0004-parallel-backup-testcase.patchDownload
From 35fd5cf5701010cebacd1be3ebd1d9f7af841d3a Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 4/4] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 571 ++++++++++++++++++
 1 file changed, 571 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..6c31214f3d
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,571 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 106;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+foreach my $filename (
+	qw(base.0.tar base.1.tar base.2.tar base.3.tar))
+{
+	ok(!-f "$tempdir/backup/$filename", "backup $filename tar created");
+}
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# Tar format doesn't support filenames longer than 100 bytes.
+my $superlongname = "superlongname_" . ("x" x 100);
+my $superlongpath = "$pgdata/$superlongname";
+
+open my $file, '>', "$superlongpath"
+  or die "unable to create file $superlongpath";
+close $file;
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft', "-j 4" ],
+	'pg_basebackup tar with long name fails');
+unlink "$pgdata/$superlongname";
+
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+	# Create a temporary directory in the system location and symlink it
+	# to our physical temp location.  That way we can use shorter names
+	# for the tablespace directories, which hopefully won't run afoul of
+	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup2", '-Ft', "-j 4" ],
+		'tar format with tablespaces');
+	ok(-f "$tempdir/tarbackup2/base.0.tar", 'backup tar was created');
+	my @tblspc_tars = glob "$tempdir/tarbackup2/[0-9]*.tar";
+	is(scalar(@tblspc_tars), 3, 'one tablespace tar was created');
+	rmtree("$tempdir/tarbackup2");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+
+	mkdir "$tempdir/$superlongname";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc3 LOCATION '$tempdir/$superlongname';");
+	$node->command_ok(
+		[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l3", '-Ft' , '-j 4'],
+		'pg_basebackup tar with long symlink target');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc3;");
+	rmtree("$tempdir/tarbackup_l3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxst", '-X', 'stream', '-Ft' , "-j 4"],
+	'pg_basebackup -X stream runs in tar mode');
+ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created");
+rmtree("$tempdir/backupxst");
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+#$node->command_checks_all(
+#	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt3", '-j 4'],
+#	1,
+#	[qr{^$}],
+#	[qr/^WARNING.*checksum verification failed/s],
+#	'pg_basebackup correctly report the total number of checksum mismatches');
+#rmtree("$tempdir/backup_corrupt3");
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.0 (Apple Git-122)

0003-pg_basebackup-changes-for-parallel-backup.patchapplication/octet-stream; name=0003-pg_basebackup-changes-for-parallel-backup.patchDownload
From 245b10802490fafeba7b17779e5c2860fbc1181c Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 14 Oct 2019 17:28:58 +0500
Subject: [PATCH 3/4] pg_basebackup changes for parallel backup.

---
 src/bin/pg_basebackup/pg_basebackup.c | 583 ++++++++++++++++++++++++--
 1 file changed, 548 insertions(+), 35 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 55ef13926d..311c1f94ca 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -41,6 +41,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -57,6 +58,37 @@ typedef struct TablespaceList
 	TablespaceListCell *tail;
 } TablespaceList;
 
+typedef struct
+{
+	char		name[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
+typedef struct
+{
+	Oid			tblspcOid;
+	char	   *tablespace;	/* tablespace name or NULL if 'base' tablespace */
+	int			numFiles;		/* number of files */
+	BackupFile *backupFiles; /* list of files in tablespace */
+} TablespaceInfo;
+
+typedef struct
+{
+	int 	tablespacecount;
+	int		numWorkers;
+
+	char	xlogstart[64];
+	char   *backup_label;
+	char   *tablespace_map;
+
+	TablespaceInfo *tsInfo;
+	SimpleStringList **worker_files;
+} BackupInfo;
+
+static BackupInfo *backupInfo = NULL;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -110,6 +142,10 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+static SimpleOidList workerspid = {NULL, NULL};
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -141,7 +177,7 @@ static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
 
-static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
+static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum, int worker);
 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
 
@@ -151,6 +187,16 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupEnd(void);
+static void GetBackupFilesList(PGconn *conn, BackupInfo *binfo);
+static int	ReceiveFiles(BackupInfo *backupInfo, int worker);
+static int	compareFileSize(const void *a, const void *b);
+static void create_workers_and_fetch(BackupInfo *backupInfo);
+static void read_label_tblspcmap(PGconn *conn, char **backup_label, char **tablespace_map);
+static void create_backup_dirs(bool basetablespace, char *tablespace, char *name);
+static void writefile(char *path, char *buf);
+static int	simple_list_length(SimpleStringList *list);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -349,6 +395,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -921,7 +968,7 @@ writeTarData(
  * No attempt to inspect or validate the contents of the file is done.
  */
 static void
-ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
+ReceiveTarFile(PGconn *conn, PGresult *res, int rownum, int worker)
 {
 	char		filename[MAXPGPATH];
 	char	   *copybuf = NULL;
@@ -978,7 +1025,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 #ifdef HAVE_LIBZ
 			if (compresslevel != 0)
 			{
-				snprintf(filename, sizeof(filename), "%s/base.tar.gz", basedir);
+				if (numWorkers > 1)
+					snprintf(filename, sizeof(filename), "%s/base.%d.tar.gz", basedir, worker);
+				else
+					snprintf(filename, sizeof(filename), "%s/base.tar.gz", basedir);
 				ztarfile = gzopen(filename, "wb");
 				if (gzsetparams(ztarfile, compresslevel,
 								Z_DEFAULT_STRATEGY) != Z_OK)
@@ -991,7 +1041,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			else
 #endif
 			{
-				snprintf(filename, sizeof(filename), "%s/base.tar", basedir);
+				if (numWorkers > 1)
+					snprintf(filename, sizeof(filename), "%s/base.%d.tar", basedir, worker);
+				else
+					snprintf(filename, sizeof(filename), "%s/base.tar", basedir);
 				tarfile = fopen(filename, "wb");
 			}
 		}
@@ -1004,8 +1057,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 #ifdef HAVE_LIBZ
 		if (compresslevel != 0)
 		{
-			snprintf(filename, sizeof(filename), "%s/%s.tar.gz", basedir,
-					 PQgetvalue(res, rownum, 0));
+			if (numWorkers > 1)
+				snprintf(filename, sizeof(filename), "%s/%s.%d.tar.gz", basedir,
+						 PQgetvalue(res, rownum, 0), worker);
+			else
+				snprintf(filename, sizeof(filename), "%s/%s.tar.gz", basedir,
+						 PQgetvalue(res, rownum, 0));
 			ztarfile = gzopen(filename, "wb");
 			if (gzsetparams(ztarfile, compresslevel,
 							Z_DEFAULT_STRATEGY) != Z_OK)
@@ -1018,8 +1075,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		else
 #endif
 		{
-			snprintf(filename, sizeof(filename), "%s/%s.tar", basedir,
-					 PQgetvalue(res, rownum, 0));
+			if (numWorkers > 1)
+				snprintf(filename, sizeof(filename), "%s/%s.%d.tar", basedir,
+						 PQgetvalue(res, rownum, 0), worker);
+			else
+				snprintf(filename, sizeof(filename), "%s/%s.tar", basedir,
+						 PQgetvalue(res, rownum, 0));
 			tarfile = fopen(filename, "wb");
 		}
 	}
@@ -1082,6 +1143,45 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 
 			MemSet(zerobuf, 0, sizeof(zerobuf));
 
+			if (numWorkers > 1 && basetablespace && worker == 0)
+			{
+				char		header[512];
+				int			padding;
+				int			len;
+
+				/* add backup_label and tablespace_map files to the tar */
+				len = strlen(backupInfo->backup_label);
+				tarCreateHeader(header,
+								"backup_label",
+								NULL,
+								len,
+								pg_file_create_mode, 04000, 02000,
+								time(NULL));
+
+				padding = ((len + 511) & ~511) - len;
+				WRITE_TAR_DATA(header, sizeof(header));
+				WRITE_TAR_DATA(backupInfo->backup_label, len);
+				if (padding)
+					WRITE_TAR_DATA(zerobuf, padding);
+
+				if (backupInfo->tablespace_map)
+				{
+					len = strlen(backupInfo->tablespace_map);
+					tarCreateHeader(header,
+									"tablespace_map",
+									NULL,
+									len,
+									pg_file_create_mode, 04000, 02000,
+									time(NULL));
+
+					padding = ((len + 511) & ~511) - len;
+					WRITE_TAR_DATA(header, sizeof(header));
+					WRITE_TAR_DATA(backupInfo->tablespace_map, len);
+					if (padding)
+						WRITE_TAR_DATA(zerobuf, padding);
+				}
+			}
+
 			if (basetablespace && writerecoveryconf)
 			{
 				char		header[512];
@@ -1475,6 +1575,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 			 */
 			snprintf(filename, sizeof(filename), "%s/%s", current_path,
 					 copybuf);
+
 			if (filename[strlen(filename) - 1] == '/')
 			{
 				/*
@@ -1486,21 +1587,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * Directory
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
+
+					/*
+					 * In parallel mode, we create directories before fetching
+					 * files so its Ok if a directory already exist.
+					 */
 					if (mkdir(filename, pg_dir_create_mode) != 0)
 					{
-						/*
-						 * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
-						 * clusters) will have been created by the wal
-						 * receiver process. Also, when the WAL directory
-						 * location was specified, pg_wal (or pg_xlog) has
-						 * already been created as a symbolic link before
-						 * starting the actual backup. So just ignore creation
-						 * failures on related directories.
-						 */
-						if (!((pg_str_endswith(filename, "/pg_wal") ||
-							   pg_str_endswith(filename, "/pg_xlog") ||
-							   pg_str_endswith(filename, "/archive_status")) &&
-							  errno == EEXIST))
+						if (errno != EEXIST)
 						{
 							pg_log_error("could not create directory \"%s\": %m",
 										 filename);
@@ -1528,8 +1622,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * can map them too.)
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
-
 					mapped_tblspc_path = get_tablespace_mapping(&copybuf[157]);
+
 					if (symlink(mapped_tblspc_path, filename) != 0)
 					{
 						pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
@@ -1716,7 +1810,8 @@ BaseBackup(void)
 	}
 
 	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+		psprintf("%s LABEL '%s' %s %s %s %s %s %s %s",
+				 (numWorkers > 1) ? "START_BACKUP" : "BASE_BACKUP",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
 				 includewal == FETCH_WAL ? "WAL" : "",
@@ -1774,7 +1869,7 @@ BaseBackup(void)
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1830,20 +1925,62 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		backupInfo = palloc0(sizeof(BackupInfo));
+
+		backupInfo->tablespacecount = tablespacecount;
+		backupInfo->numWorkers = numWorkers;
+		strlcpy(backupInfo->xlogstart, xlogstart, sizeof(backupInfo->xlogstart));
+		read_label_tblspcmap(conn, &backupInfo->backup_label, &backupInfo->tablespace_map);
+
+		/* retrive backup files from server. **/
+		GetBackupFilesList(conn, backupInfo);
+
+		/*
+		 * add backup_label in backup, (for tar format, ReceiveTarFile() will
+		 * takecare of it).
+		 */
+		if (format == 'p')
+			writefile("backup_label", backupInfo->backup_label);
+
+		/*
+		 * The backup files list is already in descending order, distribute it
+		 * to workers.
+		 */
+		backupInfo->worker_files = palloc0(sizeof(SimpleStringList) * tablespacecount);
+		for (i = 0; i < backupInfo->tablespacecount; i++)
+		{
+			TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+
+			backupInfo->worker_files[i] = palloc0(sizeof(SimpleStringList) * numWorkers);
+			for (int j = 0; j < curTsInfo->numFiles; j++)
+			{
+				simple_string_list_append(&backupInfo->worker_files[i][j % numWorkers],
+										  curTsInfo->backupFiles[j].name);
+			}
+		}
+
+		create_workers_and_fetch(backupInfo);
+		ParallelBackupEnd();
+	}
+	else
+	{
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i, 0);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+	}
 
 	if (showprogress)
 	{
-		progress_report(PQntuples(res), NULL, true);
+		progress_report(PQntuples(tablespacehdr), NULL, true);
 		if (isatty(fileno(stderr)))
 			fprintf(stderr, "\n");	/* Need to move to next line */
 	}
@@ -2043,6 +2180,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2070,7 +2208,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2211,6 +2349,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2325,6 +2466,14 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2397,3 +2546,367 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+static void
+ParallelBackupEnd(void)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP LABEL '%s' %s %s",
+					   backupInfo->backup_label,
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	if (format == 't')
+		ReceiveTarFile(conn, res, tablespacecount, numWorkers);
+	else
+		ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+
+	PQclear(res);
+}
+
+static void
+GetBackupFilesList(PGconn *conn, BackupInfo *backupInfo)
+{
+	int			i;
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	backupInfo->tsInfo = palloc0(sizeof(TablespaceInfo) * backupInfo->tablespacecount);
+	TablespaceInfo *tsInfo = backupInfo->tsInfo;
+
+	/*
+	 * Get list of files.
+	 */
+	basebkp = psprintf("SEND_FILE_LIST %s",
+					   format == 't' ? "TABLESPACE_MAP" : "");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SEND_FILE_LIST", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * The list of files is grouped by tablespaces, and we want to fetch them
+	 * in the same order.
+	 */
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		bool		basetablespace;
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tsInfo[i].tblspcOid = atol(PQgetvalue(tablespacehdr, i, 0));
+		tsInfo[i].tablespace = PQgetvalue(tablespacehdr, i, 1);
+		tsInfo[i].numFiles = PQntuples(res);
+		tsInfo[i].backupFiles =
+			palloc0(sizeof(BackupFile) * tsInfo[i].numFiles);
+
+		for (int j = 0; j < tsInfo[i].numFiles; j++)
+		{
+			char	   *name = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+				create_backup_dirs(basetablespace, tsInfo[i].tablespace, name);
+
+			strlcpy(tsInfo[i].backupFiles[j].name, name, MAXPGPATH);
+			tsInfo[i].backupFiles[j].type = type;
+			tsInfo[i].backupFiles[j].size = size;
+			tsInfo[i].backupFiles[j].mtime = mtime;
+		}
+
+		/* sort files in descending order, based on size */
+		qsort(tsInfo[i].backupFiles, tsInfo[i].numFiles,
+			  sizeof(BackupFile), &compareFileSize);
+		PQclear(res);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+}
+
+static int
+ReceiveFiles(BackupInfo *backupInfo, int worker)
+{
+	SimpleStringListCell *cell;
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn;
+	int			i;
+
+	worker_conn = GetConnection();
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+		SimpleStringList *files = &backupInfo->worker_files[i][worker];
+		PQExpBuffer buf = createPQExpBuffer();
+
+		if (simple_list_length(files) <= 0)
+			continue;
+
+
+		/*
+		 * build query in form of: SEND_FILES_CONTENT ('base/1/1245/32683',
+		 * 'base/1/1245/32683', ...) [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_FILES_CONTENT (");
+		for (cell = files->head; cell; cell = cell->next)
+		{
+			if (cell != files->tail)
+				appendPQExpBuffer(buf, "'%s' ,", cell->val);
+			else
+				appendPQExpBuffer(buf, "'%s'", cell->val);
+		}
+		appendPQExpBufferStr(buf, ")");
+
+		/*
+		 * Add backup options to the command. we are reusing the LABEL here to
+		 * keep the original tablespace path on the server.
+		 */
+		appendPQExpBuffer(buf, " LABEL '%s' LSN '%s' %s %s",
+						  curTsInfo->tablespace,
+						  backupInfo->xlogstart,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+
+		destroyPQExpBuffer(buf);
+		if (format == 't')
+			ReceiveTarFile(worker_conn, tablespacehdr, i, worker);
+		else
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, i);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	PQfinish(worker_conn);
+
+	return 0;
+}
+
+/* qsort comparator for BackupFile (sort descending order)  */
+static int
+compareFileSize(const void *a, const void *b)
+{
+	const		BackupFile *v1 = (BackupFile *) a;
+	const		BackupFile *v2 = (BackupFile *) b;
+
+	if (v1->size > v2->size)
+		return -1;
+	if (v1->size < v2->size)
+		return 1;
+
+	return 0;
+}
+
+static void
+create_workers_and_fetch(BackupInfo *backupInfo)
+{
+	int			status;
+	int			pid,
+				i;
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		pid = fork();
+		if (pid == 0)
+		{
+			/* in child process */
+			_exit(ReceiveFiles(backupInfo, i));
+		}
+		else if (pid < 0)
+		{
+			pg_log_error("could not create backup worker: %m");
+			exit(1);
+		}
+
+		simple_oid_list_append(&workerspid, pid);
+		if (verbose)
+			pg_log_info("backup worker (%d) created", pid);
+
+		/*
+		 * Else we are in the parent process and all is well.
+		 */
+	}
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		pid = waitpid(-1, &status, 0);
+
+		if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_FAILURE)
+		{
+			SimpleOidListCell *cell;
+
+			pg_log_error("backup worker (%d) failed with code %d", pid, WEXITSTATUS(status));
+
+			/* error. kill other workers and exit. */
+			for (cell = workerspid.head; cell; cell = cell->next)
+			{
+				if (pid != cell->val)
+				{
+					kill(cell->val, SIGTERM);
+					pg_log_error("backup worker killed %d", cell->val);
+				}
+			}
+
+			exit(1);
+		}
+	}
+}
+
+static void
+read_label_tblspcmap(PGconn *conn, char **backuplabel, char **tblspc_map)
+{
+	PGresult   *res = NULL;
+
+	Assert(backuplabel != NULL);
+	Assert(tblspc_map != NULL);
+
+	/*
+	 * Get Backup label and tablespace map data.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) < 1)
+	{
+		pg_log_error("no data returned from server");
+		exit(1);
+	}
+
+	*backuplabel = PQgetvalue(res, 0, 0);	/* backup_label */
+	if (!PQgetisnull(res, 0, 1))
+		*tblspc_map = PQgetvalue(res, 0, 1);	/* tablespae_map */
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	PQclear(res);
+}
+
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char	dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+static void
+writefile(char *path, char *buf)
+{
+	FILE   *f;
+	char	pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
+
+static int
+simple_list_length(SimpleStringList *list)
+{
+	int			len = 0;
+	SimpleStringListCell *cell;
+
+	for (cell = list->head; cell; cell = cell->next, len++)
+		;
+
+	return len;
+}
-- 
2.21.0 (Apple Git-122)

0002-backend-changes-for-parallel-backup.patchapplication/octet-stream; name=0002-backend-changes-for-parallel-backup.patchDownload
From 3e62b74a0e8d22df942f625a343d1d6254ad1b08 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 22:59:28 +0500
Subject: [PATCH 2/4] backend changes for parallel backup

---
 src/backend/replication/basebackup.c   | 589 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    |  72 +++
 src/backend/replication/repl_scanner.l |   7 +
 src/include/nodes/replnodes.h          |  10 +
 src/include/replication/basebackup.h   |   2 +-
 5 files changed, 670 insertions(+), 10 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index a05a97ded2..cc262e49b8 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -41,6 +41,7 @@
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
+#include "utils/pg_lsn.h"
 
 
 typedef struct
@@ -52,11 +53,34 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	bool		exclusive;
+	XLogRecPtr	lsn;
 } basebackup_options;
 
+typedef struct
+{
+	char		name[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
+#define STORE_BACKUPFILE(_backupfiles, _name, _type, _size, _mtime) \
+	do { \
+		if (_backupfiles != NULL) { \
+			BackupFile *file = palloc0(sizeof(BackupFile)); \
+			strlcpy(file->name, _name, sizeof(file->name)); \
+			file->type = _type; \
+			file->size = _size; \
+			file->mtime = _mtime; \
+			*_backupfiles = lappend(*_backupfiles, file); \
+		} \
+	} while(0)
 
 static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
 					 List *tablespaces, bool sendtblspclinks);
+static int64 sendDir_(const char *path, int basepathlen, bool sizeonly,
+					  List *tablespaces, bool sendtblspclinks, List **files);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -76,6 +100,12 @@ static void throttle(size_t increment);
 static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendFileList(basebackup_options *opt);
+static void SendFilesContents(basebackup_options *opt, List *filenames, bool missing_ok);
+static char *readfile(const char *readfilename, bool missing_ok);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -338,7 +368,7 @@ perform_base_backup(basebackup_options *opt)
 				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 			}
 			else
-				sendTablespace(ti->path, false);
+				sendTablespace(ti->path, false, NULL);
 
 			/*
 			 * If we're including WAL, and this is the main data directory we
@@ -413,6 +443,8 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_exclusive = false;
+	bool		o_lsn = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -501,6 +533,30 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "exclusive") == 0)
+		{
+			if (o_exclusive)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			opt->exclusive = intVal(defel->arg);
+			o_exclusive = true;
+		}
+		else if (strcmp(defel->defname, "lsn") == 0)
+		{
+			bool		have_error = false;
+			char	   *lsn;
+
+			if (o_lsn)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			lsn = strVal(defel->arg);
+			opt->lsn = pg_lsn_in_internal(lsn, &have_error);
+			o_lsn = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -535,7 +591,29 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_FILE_LIST:
+			SendFileList(&opt);
+			break;
+		case SEND_FILES_CONTENT:
+			SendFilesContents(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -678,6 +756,61 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_puttextmessage('C', "SELECT");
 }
 
+/*
+ * Send a single resultset containing backup label and tablespace map
+ */
+static void
+SendStartBackupResult(StringInfo labelfile, StringInfo tblspc_map_file)
+{
+	StringInfoData buf;
+	Size		len;
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);		/* 2 fields */
+
+	/* Field headers */
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "tablespacemap");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint16(&buf, 2);		/* number of columns */
+
+	len = labelfile->len;
+	pq_sendint32(&buf, len);
+	pq_sendbytes(&buf, labelfile->data, len);
+
+	if (tblspc_map_file)
+	{
+		len = tblspc_map_file->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, tblspc_map_file->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
+	}
+
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -729,7 +862,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool sizeonly, List **files)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -758,11 +891,11 @@ sendTablespace(char *path, bool sizeonly)
 		return 0;
 	}
 
+	STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   sizeonly);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir_(pathbuf, strlen(path), sizeonly, NIL, true, files);
 
 	return size;
 }
@@ -780,8 +913,16 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
-		bool sendtblspclinks)
+sendDir(const char *path, int basepathlen, bool sizeonly,
+		List *tablespaces, bool sendtblspclinks)
+{
+	return sendDir_(path, basepathlen, sizeonly, tablespaces, sendtblspclinks, NULL);
+}
+
+/* Same as sendDir(), except that it also returns a list of filenames in PGDATA */
+static int64
+sendDir_(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+		 bool sendtblspclinks, List **files)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -935,6 +1076,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 				excludeFound = true;
 				break;
@@ -951,6 +1094,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 			continue;
 		}
@@ -972,6 +1117,9 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									sizeonly);
 
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
+			STORE_BACKUPFILE(files, "./pg_wal/archive_status", 'd', -1, statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -1001,6 +1149,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			STORE_BACKUPFILE(files, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, sizeonly);
 #else
@@ -1027,6 +1176,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									sizeonly);
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
+
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1057,13 +1208,15 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir_(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks, files);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			STORE_BACKUPFILE(files, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!sizeonly && files == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1769,3 +1922,421 @@ setup_throttle(int maxrate)
 		throttling_counter = -1;
 	}
 }
+
+/*
+ * StartBackup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  opt->exclusive? NULL : labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, *all* functionality between do_pg_start_backup() and the end of
+	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 */
+
+	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	{
+		tablespaceinfo *ti;
+
+		SendXlogRecPtrResult(startptr, starttli);
+
+		/*
+		 * Calculate the relative path of temporary statistics directory in
+		 * order to skip the files which are located in that directory later.
+		 */
+		if (is_absolute_path(pgstat_stat_directory) &&
+			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory);
+		else
+			statrelpath = pgstat_stat_directory;
+
+		/* Add a node for the base directory at the end */
+		ti = palloc0(sizeof(tablespaceinfo));
+		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+		tablespaces = lappend(tablespaces, ti);
+
+		/* Send tablespace header */
+		SendBackupHeader(tablespaces);
+
+		/* Setup and activate network throttling, if client requested it */
+		setup_throttle(opt->maxrate);
+
+		/*
+		 * In exclusive mode, pg_start_backup creates backup_label and
+		 * tablespace_map files and does not their contents in *labelfile
+		 * and *tblspcmapfile. So we read them from these files to return
+		 * to frontend.
+		 *
+		 * In non-exlusive mode, contents of these files are available in
+		 * *labelfile and *tblspcmapfile and are retured directly.
+		 */
+		if (opt->exclusive)
+		{
+			resetStringInfo(labelfile);
+			resetStringInfo(tblspc_map_file);
+
+			appendStringInfoString(labelfile, readfile(BACKUP_LABEL_FILE, false));
+			if (opt->sendtblspcmapfile)
+				appendStringInfoString(tblspc_map_file, readfile(TABLESPACE_MAP, false));
+		}
+
+		if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
+			!opt->sendtblspcmapfile)
+			tblspc_map_file = NULL;
+
+		/* send backup_label and tablespace_map to frontend */
+		SendStartBackupResult(labelfile, tblspc_map_file);
+	}
+	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+}
+
+/*
+ * StopBackup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionaly WAL segments and ending WAL location.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile = NULL;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	/* stop backup */
+	if (!opt->exclusive)
+		labelfile = (char *) opt->label;
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	if (opt->includewal)
+		include_wal_files(endptr, endtli);
+
+	pq_putemptymessage('c');	/* CopyDone */
+	SendXlogRecPtrResult(endptr, endtli);
+}
+
+/*
+ * SendFileList() - sends a list of filenames to frontend
+ *
+ * The function collects a list of filenames, nessery for a complete backup and
+ * sends this list to the client.
+ */
+static void
+SendFileList(basebackup_options *opt)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	List	   *tablespaces = NIL;
+	StringInfo	tblspc_map_file = NULL;
+
+	tblspc_map_file = makeStringInfo();
+	collectTablespaces(&tablespaces, tblspc_map_file, false, false);
+
+	/* Add a node for the base directory at the end */
+	tablespaceinfo *ti = palloc0(sizeof(tablespaceinfo));
+	tablespaces = lappend(tablespaces, ti);
+
+	foreach(lc, tablespaces)
+	{
+		List	   *backupFiles = NULL;
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+
+		if (ti->path == NULL)
+			sendDir_(".", 1, false, NIL, !opt->sendtblspcmapfile, &backupFiles);
+		else
+			sendTablespace(ti->path, false, &backupFiles);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 4);	/* n field */
+
+		/* First field - file name */
+		pq_sendstring(&buf, "filename");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "type");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, CHAROID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - mtime */
+		pq_sendstring(&buf, "mtime");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, backupFiles)
+		{
+			BackupFile *backupFile = (BackupFile *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 4);	/* number of columns */
+
+			/* send file name */
+			len = strlen(backupFile->name);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, backupFile->name, len);
+
+			/* send type */
+			pq_sendint32(&buf, 1);
+			pq_sendbyte(&buf, backupFile->type);
+
+			/* send size */
+			send_int8_string(&buf, backupFile->size);
+
+			/* send mtime */
+			send_int8_string(&buf, backupFile->mtime);
+
+			pq_endmessage(&buf);
+		}
+
+		pfree(backupFiles);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendFilesContents() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol.
+ */
+static void
+SendFilesContents(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	bool		basetablespace = true;
+	int			basepathlen = 1;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/*
+	 * LABEL is reused here to identify the tablespace path on server. Its empty
+	 * in case of 'base' tablespace.
+	 */
+	if (is_absolute_path(opt->label))
+	{
+		basepathlen = strlen(opt->label);
+		basetablespace = false;
+	}
+
+	/* set backup start location. */
+	startptr = opt->lsn;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/* Allow symbolic links in pg_tblspc only */
+		if (strstr(pathbuf, "./pg_tblspc") != NULL &&
+#ifndef WIN32
+			S_ISLNK(statbuf.st_mode)
+#else
+			pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			char		linkpath[MAXPGPATH];
+			int			rllen;
+
+			rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not read symbolic link \"%s\": %m",
+								pathbuf)));
+			if (rllen >= sizeof(linkpath))
+				ereport(ERROR,
+						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+						 errmsg("symbolic link \"%s\" target is too long",
+								pathbuf)));
+			linkpath[rllen] = '\0';
+
+			_tarWriteHeader(pathbuf, linkpath, &statbuf, false);
+		}
+		else if (S_ISDIR(statbuf.st_mode))
+		{
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else if (
+#ifndef WIN32
+				 S_ISLNK(statbuf.st_mode)
+#else
+				 pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			/*
+			 * If symlink, write it as a directory. file symlinks only allowed
+			 * in pg_tblspc
+			 */
+			statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report totoal checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+static char *
+readfile(const char *readfilename, bool missing_ok)
+{
+	struct stat statbuf;
+	FILE	   *fp;
+	char	   *data;
+	int			r;
+
+	if (stat(readfilename, &statbuf))
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						readfilename)));
+	}
+
+	fp = AllocateFile(readfilename, "r");
+	if (!fp)
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not open file \"%s\": %m", readfilename)));
+	}
+
+	data = palloc(statbuf.st_size + 1);
+	r = fread(data, statbuf.st_size, 1, fp);
+	data[statbuf.st_size] = '\0';
+
+	/* Close the file */
+	if (r != 1 || ferror(fp) || FreeFile(fp))
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not read file \"%s\": %m",
+						readfilename)));
+
+	return data;
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..bba437c785 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,6 +87,12 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_FILE_LIST
+%token K_SEND_FILES_CONTENT
+%token K_STOP_BACKUP
+%token K_EXCLUSIVE
+%token K_LSN
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
@@ -102,6 +108,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -162,6 +170,36 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_START_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILE_LIST base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = SEND_FILE_LIST;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILES_CONTENT backup_files base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_FILES_CONTENT;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
@@ -214,6 +252,40 @@ base_backup_opt:
 				  $$ = makeDefElem("noverify_checksums",
 								   (Node *)makeInteger(true), -1);
 				}
+			| K_EXCLUSIVE
+				{
+				  $$ = makeDefElem("exclusive",
+								   (Node *)makeInteger(true), -1);
+				}
+			| K_LSN SCONST
+				{
+				  $$ = makeDefElem("lsn",
+								   (Node *)makeString($2), -1);
+				}
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{
+					$$ = $2;
+				}
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
+				{
+					$$ = list_make1($1);
+				}
+			| backup_files_list ',' backup_file
+				{
+					$$ = lappend($1, $3);
+				}
+			;
+
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..f97fe804ff 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,13 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_FILE_LIST		{ return K_SEND_FILE_LIST; }
+SEND_FILES_CONTENT	{ return K_SEND_FILES_CONTENT; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+EXCLUSIVE			{ return K_EXCLUSIVE; }
+LSN					{ return K_LSN; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..1a224122a2 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,14 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_FILE_LIST,
+	SEND_FILES_CONTENT,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +50,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..9e792af99d 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool sizeonly, List **files);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122)

#22Jeevan Ladhe
jeevan.ladhe@enterprisedb.com
In reply to: Asif Rehman (#21)
Re: WIP/PoC for parallel backup

I quickly tried to have a look at your 0001-refactor patch.
Here are some comments:

1. The patch fails to compile.

Sorry if I am missing something, but am not able to understand why in new
function collectTablespaces() you have added an extra parameter NULL while
calling sendTablespace(), it fails the compilation :

+ ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;

gcc -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Werror=vla -Wendif-labels
-Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv
-Wno-unused-command-line-argument -g -g -O0 -Wall -Werror
-I../../../../src/include -c -o xlog.o xlog.c -MMD -MP -MF .deps/xlog.Po
xlog.c:12253:59: error: too many arguments to function call, expected 2,
have 3
ti->size = infotbssize ? sendTablespace(fullpath, true,
NULL) : -1;
~~~~~~~~~~~~~~ ^~~~

2. I think the patch needs to run via pg_indent. It does not follow 80
column
width.
e.g.

+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile, bool
infotbssize, bool needtblspcmapfile)
+{

3.
The comments in re-factored code appear to be redundant. example:
Following comment:
/* Setup and activate network throttling, if client requested it */
appears thrice in the code, before calling setup_throttle(), in the
prologue of
the function setup_throttle(), and above the if() in that function.
Similarly - the comment:
/* Collect information about all tablespaces */
in collectTablespaces().

4.
In function include_wal_files() why is the parameter TimeLineID i.e. endtli
needed. I don't see it being used in the function at all. I think you can
safely
get rid of it.

+include_wal_files(XLogRecPtr endptr, TimeLineID endtli)

Regards,
Jeevan Ladhe

On Wed, Oct 16, 2019 at 6:49 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Show quoted text

On Mon, Oct 7, 2019 at 6:35 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Mon, Oct 7, 2019 at 6:05 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Oct 7, 2019 at 8:48 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Sure. Though the backup manifest patch calculates and includes the

checksum of backup files and is done

while the file is being transferred to the frontend-end. The manifest

file itself is copied at the

very end of the backup. In parallel backup, I need the list of

filenames before file contents are transferred, in

order to divide them into multiple workers. For that, the manifest

file has to be available when START_BACKUP

is called.

That means, backup manifest should support its creation while

excluding the checksum during START_BACKUP().

I also need the directory information as well for two reasons:

- In plain format, base path has to exist before we can write the

file. we can extract the base path from the file

but doing that for all files does not seem a good idea.
- base backup does not include the content of some directories but

those directories although empty, are still

expected in PGDATA.

I can make these changes part of parallel backup (which would be on

top of backup manifest patch) or

these changes can be done as part of manifest patch and then parallel

can use them.

Robert what do you suggest?

I think we should probably not use backup manifests here, actually. I
initially thought that would be a good idea, but after further thought
it seems like it just complicates the code to no real benefit.

Okay.

I
suggest that the START_BACKUP command just return a result set, like a
query, with perhaps four columns: file name, file type ('d' for
directory or 'f' for file), file size, file mtime. pg_basebackup will
ignore the mtime, but some other tools might find that useful
information.

yes current patch already returns the result set. will add the additional
information.

I wonder if we should also split START_BACKUP (which should enter
non-exclusive backup mode) from GET_FILE_LIST, in case some other
client program wants to use one of those but not the other. I think
that's probably a good idea, but not sure.

Currently pg_basebackup does not enter in exclusive backup mode and other
tools have to
use pg_start_backup() and pg_stop_backup() functions to achieve that.
Since we are breaking
backup into multiple command, I believe it would be a good idea to have
this option. I will include
it in next revision of this patch.

I still think that the files should be requested one at a time, not a
huge long list in a single command.

sure, will make the change.

I have refactored the functionality into multiple smaller patches in order
to make the review process easier. I have divided the code into backend
changes and pg_basebackup changes. The
backend replication system now supports the following commands:

- START_BACKUP
- SEND_FILE_LIST
- SEND_FILES_CONTENT
- STOP_BACKUP

The START_BACKUP will not return the list of files, instead SEND_FILE_LIST
is used for that. The START_BACKUP
now calls pg_start_backup and returns starting WAL position, tablespace
header information and content of backup label file.
Initially I was using tmp files to store the backup_label content but that
turns out to be bad idea, because there can be multiple
non-exclusive backups running. The backup label information is needed by
stop_backup so pg_basebackup will send it as part
of STOP_BACKUP.

The SEND_FILE_LIST will return the list of files. It will be returned as
resultset having four columns (filename, type, size, mtime).
The SEND_FILES_CONTENT can now return the single file or multiple files as
required. There is not much change required to
support both, so I believe it will be much useable this way if other tools
want to utilise it.

As per suggestion from Robert, I am currently working on making changes in
pg_basebackup to fetch files one by one. However that's not complete and
the attach patch
is still using the old method of multi-file fetching to test the backend
commands. I will send an updated patch which will contain the changes on
fetching file one by one.

I wanted to share the backend patch to get some feedback in the mean time.

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#23Asif Rehman
asifr.rehman@gmail.com
In reply to: Jeevan Ladhe (#22)
4 attachment(s)
Re: WIP/PoC for parallel backup

On Thu, Oct 17, 2019 at 1:33 AM Jeevan Ladhe <jeevan.ladhe@enterprisedb.com>
wrote:

I quickly tried to have a look at your 0001-refactor patch.
Here are some comments:

1. The patch fails to compile.

Sorry if I am missing something, but am not able to understand why in new
function collectTablespaces() you have added an extra parameter NULL while
calling sendTablespace(), it fails the compilation :

+ ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;

gcc -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Werror=vla -Wendif-labels
-Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv
-Wno-unused-command-line-argument -g -g -O0 -Wall -Werror
-I../../../../src/include -c -o xlog.o xlog.c -MMD -MP -MF .deps/xlog.Po
xlog.c:12253:59: error: too many arguments to function call, expected 2,
have 3
ti->size = infotbssize ? sendTablespace(fullpath, true,
NULL) : -1;
~~~~~~~~~~~~~~
^~~~

2. I think the patch needs to run via pg_indent. It does not follow 80
column
width.
e.g.

+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile, bool
infotbssize, bool needtblspcmapfile)
+{

3.
The comments in re-factored code appear to be redundant. example:
Following comment:
/* Setup and activate network throttling, if client requested it */
appears thrice in the code, before calling setup_throttle(), in the
prologue of
the function setup_throttle(), and above the if() in that function.
Similarly - the comment:
/* Collect information about all tablespaces */
in collectTablespaces().

4.
In function include_wal_files() why is the parameter TimeLineID i.e. endtli
needed. I don't see it being used in the function at all. I think you can
safely
get rid of it.

+include_wal_files(XLogRecPtr endptr, TimeLineID endtli)

Thanks Jeevan. Some changes that should be part of 2nd patch were left in
the 1st. I have fixed that and the above mentioned issues as well.
Attached are the updated patches.

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0001-Refactor-some-basebackup-code-to-increase-reusabilit.patchapplication/octet-stream; name=0001-Refactor-some-basebackup-code-to-increase-reusabilit.patchDownload
From f5bdfddd5efba1b66ab30c7220ae6b62b312337a Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 9 Oct 2019 12:39:41 +0500
Subject: [PATCH 1/4] Refactor some basebackup code to increase reusability, in
 anticipation of adding parallel backup

---
 src/backend/access/transam/xlog.c    | 192 +++++-----
 src/backend/replication/basebackup.c | 512 ++++++++++++++-------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 371 insertions(+), 335 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0ff9af53fe..54a430d041 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10282,10 +10282,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10411,93 +10407,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collectTablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12261,3 +12171,103 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+				   bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to
+		 * ensure that we can distinguish between the newline in the
+		 * tablespace path and end of line while reading tablespace_map
+		 * file during archive recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory
+		 * when it's located within PGDATA, or NULL if it's located
+		 * elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created
+		 * them. Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index d0f210de8c..5f25f5848d 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -68,10 +68,12 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt);
+static void include_wal_files(XLogRecPtr endptr);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
+static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
@@ -293,29 +295,7 @@ perform_base_backup(basebackup_options *opt)
 		/* Send tablespace header */
 		SendBackupHeader(tablespaces);
 
-		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
-
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		setup_throttle(opt->maxrate);
 
 		/* Send off our tablespaces one by one */
 		foreach(lc, tablespaces)
@@ -384,227 +364,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -1743,3 +1503,267 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * Append the required WAL files to the backup tar file. It assumes that the
+ * last tar file is "open" and the WALs will be appended to it.
+ */
+static void
+include_wal_files(XLogRecPtr endptr)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the
+	 * required WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and
+	 * include all WAL files in the range between 'startptr' and 'endptr',
+	 * regardless of the timeline the file is stamped with. If there are
+	 * some spurious WAL files belonging to timelines that don't belong in
+	 * this server's history, they will be included too. Normally there
+	 * shouldn't be such files, but if there are, there's little harm in
+	 * including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we
+	 * need were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from
+	 * oldest to newest, to reduce the chance that a file is recycled
+	 * before we get a chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since
+	 * we are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		CHECK_FREAD_ERROR(fp, pathbuf);
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again
+		 * after promotion of a new node. This is in line with
+		 * walreceiver.c always doing an XLogArchiveForceDone() after a
+		 * complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history
+	 * file is required for recovery, and even that only if there happens
+	 * to be a timeline switch in the first WAL segment that contains the
+	 * checkpoint record, or if we're taking a base backup from a standby
+	 * server and the target timeline changes while the backup is taken.
+	 * But they are small and highly useful for debugging purposes, so
+	 * better include them all, always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d519252aad..5b0aa8ae85 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 									 bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
+extern void collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+							   bool infotbssize, bool needtblspcmapfile);
 extern void do_pg_abort_backup(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.0 (Apple Git-122)

0002-backend-changes-for-parallel-backup.patchapplication/octet-stream; name=0002-backend-changes-for-parallel-backup.patchDownload
From b60e132d16ddd026b48fc095a285458725ec74ca Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 22:59:28 +0500
Subject: [PATCH 2/4] backend changes for parallel backup

---
 src/backend/access/transam/xlog.c      |   2 +-
 src/backend/replication/basebackup.c   | 589 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    |  72 +++
 src/backend/replication/repl_scanner.l |   7 +
 src/include/nodes/replnodes.h          |  10 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 671 insertions(+), 11 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 54a430d041..eafa531389 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -12249,7 +12249,7 @@ collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 5f25f5848d..e77e0114e1 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -41,6 +41,7 @@
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
+#include "utils/pg_lsn.h"
 
 
 typedef struct
@@ -52,11 +53,34 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	bool		exclusive;
+	XLogRecPtr	lsn;
 } basebackup_options;
 
+typedef struct
+{
+	char		name[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
+#define STORE_BACKUPFILE(_backupfiles, _name, _type, _size, _mtime) \
+	do { \
+		if (_backupfiles != NULL) { \
+			BackupFile *file = palloc0(sizeof(BackupFile)); \
+			strlcpy(file->name, _name, sizeof(file->name)); \
+			file->type = _type; \
+			file->size = _size; \
+			file->mtime = _mtime; \
+			*_backupfiles = lappend(*_backupfiles, file); \
+		} \
+	} while(0)
 
 static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
 					 List *tablespaces, bool sendtblspclinks);
+static int64 sendDir_(const char *path, int basepathlen, bool sizeonly,
+					  List *tablespaces, bool sendtblspclinks, List **files);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -76,6 +100,12 @@ static void throttle(size_t increment);
 static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendFileList(basebackup_options *opt);
+static void SendFilesContents(basebackup_options *opt, List *filenames, bool missing_ok);
+static char *readfile(const char *readfilename, bool missing_ok);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -337,7 +367,7 @@ perform_base_backup(basebackup_options *opt)
 				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 			}
 			else
-				sendTablespace(ti->path, false);
+				sendTablespace(ti->path, false, NULL);
 
 			/*
 			 * If we're including WAL, and this is the main data directory we
@@ -412,6 +442,8 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_exclusive = false;
+	bool		o_lsn = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -500,6 +532,30 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "exclusive") == 0)
+		{
+			if (o_exclusive)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			opt->exclusive = intVal(defel->arg);
+			o_exclusive = true;
+		}
+		else if (strcmp(defel->defname, "lsn") == 0)
+		{
+			bool		have_error = false;
+			char	   *lsn;
+
+			if (o_lsn)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			lsn = strVal(defel->arg);
+			opt->lsn = pg_lsn_in_internal(lsn, &have_error);
+			o_lsn = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -534,7 +590,29 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_FILE_LIST:
+			SendFileList(&opt);
+			break;
+		case SEND_FILES_CONTENT:
+			SendFilesContents(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -677,6 +755,61 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_puttextmessage('C', "SELECT");
 }
 
+/*
+ * Send a single resultset containing backup label and tablespace map
+ */
+static void
+SendStartBackupResult(StringInfo labelfile, StringInfo tblspc_map_file)
+{
+	StringInfoData buf;
+	Size		len;
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);		/* 2 fields */
+
+	/* Field headers */
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "tablespacemap");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint16(&buf, 2);		/* number of columns */
+
+	len = labelfile->len;
+	pq_sendint32(&buf, len);
+	pq_sendbytes(&buf, labelfile->data, len);
+
+	if (tblspc_map_file)
+	{
+		len = tblspc_map_file->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, tblspc_map_file->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
+	}
+
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -728,7 +861,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool sizeonly, List **files)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -757,11 +890,11 @@ sendTablespace(char *path, bool sizeonly)
 		return 0;
 	}
 
+	STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   sizeonly);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir_(pathbuf, strlen(path), sizeonly, NIL, true, files);
 
 	return size;
 }
@@ -779,8 +912,16 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
-		bool sendtblspclinks)
+sendDir(const char *path, int basepathlen, bool sizeonly,
+		List *tablespaces, bool sendtblspclinks)
+{
+	return sendDir_(path, basepathlen, sizeonly, tablespaces, sendtblspclinks, NULL);
+}
+
+/* Same as sendDir(), except that it also returns a list of filenames in PGDATA */
+static int64
+sendDir_(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+		 bool sendtblspclinks, List **files)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -934,6 +1075,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 				excludeFound = true;
 				break;
@@ -950,6 +1093,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 			continue;
 		}
@@ -971,6 +1116,9 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									sizeonly);
 
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
+			STORE_BACKUPFILE(files, "./pg_wal/archive_status", 'd', -1, statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -1000,6 +1148,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			STORE_BACKUPFILE(files, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, sizeonly);
 #else
@@ -1026,6 +1175,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									sizeonly);
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
+
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1056,13 +1207,15 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir_(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks, files);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			STORE_BACKUPFILE(files, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!sizeonly && files == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1767,3 +1920,421 @@ setup_throttle(int maxrate)
 		throttling_counter = -1;
 	}
 }
+
+/*
+ * StartBackup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  opt->exclusive? NULL : labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, *all* functionality between do_pg_start_backup() and the end of
+	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 */
+
+	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	{
+		tablespaceinfo *ti;
+
+		SendXlogRecPtrResult(startptr, starttli);
+
+		/*
+		 * Calculate the relative path of temporary statistics directory in
+		 * order to skip the files which are located in that directory later.
+		 */
+		if (is_absolute_path(pgstat_stat_directory) &&
+			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory);
+		else
+			statrelpath = pgstat_stat_directory;
+
+		/* Add a node for the base directory at the end */
+		ti = palloc0(sizeof(tablespaceinfo));
+		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+		tablespaces = lappend(tablespaces, ti);
+
+		/* Send tablespace header */
+		SendBackupHeader(tablespaces);
+
+		/* Setup and activate network throttling, if client requested it */
+		setup_throttle(opt->maxrate);
+
+		/*
+		 * In exclusive mode, pg_start_backup creates backup_label and
+		 * tablespace_map files and does not their contents in *labelfile
+		 * and *tblspcmapfile. So we read them from these files to return
+		 * to frontend.
+		 *
+		 * In non-exlusive mode, contents of these files are available in
+		 * *labelfile and *tblspcmapfile and are retured directly.
+		 */
+		if (opt->exclusive)
+		{
+			resetStringInfo(labelfile);
+			resetStringInfo(tblspc_map_file);
+
+			appendStringInfoString(labelfile, readfile(BACKUP_LABEL_FILE, false));
+			if (opt->sendtblspcmapfile)
+				appendStringInfoString(tblspc_map_file, readfile(TABLESPACE_MAP, false));
+		}
+
+		if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
+			!opt->sendtblspcmapfile)
+			tblspc_map_file = NULL;
+
+		/* send backup_label and tablespace_map to frontend */
+		SendStartBackupResult(labelfile, tblspc_map_file);
+	}
+	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+}
+
+/*
+ * StopBackup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionaly WAL segments and ending WAL location.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile = NULL;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	/* stop backup */
+	if (!opt->exclusive)
+		labelfile = (char *) opt->label;
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	if (opt->includewal)
+		include_wal_files(endptr);
+
+	pq_putemptymessage('c');	/* CopyDone */
+	SendXlogRecPtrResult(endptr, endtli);
+}
+
+/*
+ * SendFileList() - sends a list of filenames to frontend
+ *
+ * The function collects a list of filenames, nessery for a complete backup and
+ * sends this list to the client.
+ */
+static void
+SendFileList(basebackup_options *opt)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	List	   *tablespaces = NIL;
+	StringInfo	tblspc_map_file = NULL;
+
+	tblspc_map_file = makeStringInfo();
+	collectTablespaces(&tablespaces, tblspc_map_file, false, false);
+
+	/* Add a node for the base directory at the end */
+	tablespaceinfo *ti = palloc0(sizeof(tablespaceinfo));
+	tablespaces = lappend(tablespaces, ti);
+
+	foreach(lc, tablespaces)
+	{
+		List	   *backupFiles = NULL;
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+
+		if (ti->path == NULL)
+			sendDir_(".", 1, false, NIL, !opt->sendtblspcmapfile, &backupFiles);
+		else
+			sendTablespace(ti->path, false, &backupFiles);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 4);	/* n field */
+
+		/* First field - file name */
+		pq_sendstring(&buf, "filename");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "type");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, CHAROID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - mtime */
+		pq_sendstring(&buf, "mtime");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, backupFiles)
+		{
+			BackupFile *backupFile = (BackupFile *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 4);	/* number of columns */
+
+			/* send file name */
+			len = strlen(backupFile->name);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, backupFile->name, len);
+
+			/* send type */
+			pq_sendint32(&buf, 1);
+			pq_sendbyte(&buf, backupFile->type);
+
+			/* send size */
+			send_int8_string(&buf, backupFile->size);
+
+			/* send mtime */
+			send_int8_string(&buf, backupFile->mtime);
+
+			pq_endmessage(&buf);
+		}
+
+		pfree(backupFiles);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendFilesContents() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol.
+ */
+static void
+SendFilesContents(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	bool		basetablespace = true;
+	int			basepathlen = 1;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/*
+	 * LABEL is reused here to identify the tablespace path on server. Its empty
+	 * in case of 'base' tablespace.
+	 */
+	if (is_absolute_path(opt->label))
+	{
+		basepathlen = strlen(opt->label);
+		basetablespace = false;
+	}
+
+	/* set backup start location. */
+	startptr = opt->lsn;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/* Allow symbolic links in pg_tblspc only */
+		if (strstr(pathbuf, "./pg_tblspc") != NULL &&
+#ifndef WIN32
+			S_ISLNK(statbuf.st_mode)
+#else
+			pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			char		linkpath[MAXPGPATH];
+			int			rllen;
+
+			rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not read symbolic link \"%s\": %m",
+								pathbuf)));
+			if (rllen >= sizeof(linkpath))
+				ereport(ERROR,
+						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+						 errmsg("symbolic link \"%s\" target is too long",
+								pathbuf)));
+			linkpath[rllen] = '\0';
+
+			_tarWriteHeader(pathbuf, linkpath, &statbuf, false);
+		}
+		else if (S_ISDIR(statbuf.st_mode))
+		{
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else if (
+#ifndef WIN32
+				 S_ISLNK(statbuf.st_mode)
+#else
+				 pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			/*
+			 * If symlink, write it as a directory. file symlinks only allowed
+			 * in pg_tblspc
+			 */
+			statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report totoal checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+static char *
+readfile(const char *readfilename, bool missing_ok)
+{
+	struct stat statbuf;
+	FILE	   *fp;
+	char	   *data;
+	int			r;
+
+	if (stat(readfilename, &statbuf))
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						readfilename)));
+	}
+
+	fp = AllocateFile(readfilename, "r");
+	if (!fp)
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not open file \"%s\": %m", readfilename)));
+	}
+
+	data = palloc(statbuf.st_size + 1);
+	r = fread(data, statbuf.st_size, 1, fp);
+	data[statbuf.st_size] = '\0';
+
+	/* Close the file */
+	if (r != 1 || ferror(fp) || FreeFile(fp))
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not read file \"%s\": %m",
+						readfilename)));
+
+	return data;
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..bba437c785 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,6 +87,12 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_FILE_LIST
+%token K_SEND_FILES_CONTENT
+%token K_STOP_BACKUP
+%token K_EXCLUSIVE
+%token K_LSN
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
@@ -102,6 +108,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -162,6 +170,36 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_START_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILE_LIST base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = SEND_FILE_LIST;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILES_CONTENT backup_files base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_FILES_CONTENT;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
@@ -214,6 +252,40 @@ base_backup_opt:
 				  $$ = makeDefElem("noverify_checksums",
 								   (Node *)makeInteger(true), -1);
 				}
+			| K_EXCLUSIVE
+				{
+				  $$ = makeDefElem("exclusive",
+								   (Node *)makeInteger(true), -1);
+				}
+			| K_LSN SCONST
+				{
+				  $$ = makeDefElem("lsn",
+								   (Node *)makeString($2), -1);
+				}
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{
+					$$ = $2;
+				}
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
+				{
+					$$ = list_make1($1);
+				}
+			| backup_files_list ',' backup_file
+				{
+					$$ = lappend($1, $3);
+				}
+			;
+
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..f97fe804ff 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,13 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_FILE_LIST		{ return K_SEND_FILE_LIST; }
+SEND_FILES_CONTENT	{ return K_SEND_FILES_CONTENT; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+EXCLUSIVE			{ return K_EXCLUSIVE; }
+LSN					{ return K_LSN; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..1a224122a2 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,14 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_FILE_LIST,
+	SEND_FILES_CONTENT,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +50,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..9e792af99d 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool sizeonly, List **files);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122)

0004-parallel-backup-testcase.patchapplication/octet-stream; name=0004-parallel-backup-testcase.patchDownload
From 2915c35ccfa0c1de0fcbd35c03ad0a9cd0f4997b Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 4/4] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 571 ++++++++++++++++++
 1 file changed, 571 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..6c31214f3d
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,571 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 106;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+foreach my $filename (
+	qw(base.0.tar base.1.tar base.2.tar base.3.tar))
+{
+	ok(!-f "$tempdir/backup/$filename", "backup $filename tar created");
+}
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# Tar format doesn't support filenames longer than 100 bytes.
+my $superlongname = "superlongname_" . ("x" x 100);
+my $superlongpath = "$pgdata/$superlongname";
+
+open my $file, '>', "$superlongpath"
+  or die "unable to create file $superlongpath";
+close $file;
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft', "-j 4" ],
+	'pg_basebackup tar with long name fails');
+unlink "$pgdata/$superlongname";
+
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+	# Create a temporary directory in the system location and symlink it
+	# to our physical temp location.  That way we can use shorter names
+	# for the tablespace directories, which hopefully won't run afoul of
+	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup2", '-Ft', "-j 4" ],
+		'tar format with tablespaces');
+	ok(-f "$tempdir/tarbackup2/base.0.tar", 'backup tar was created');
+	my @tblspc_tars = glob "$tempdir/tarbackup2/[0-9]*.tar";
+	is(scalar(@tblspc_tars), 3, 'one tablespace tar was created');
+	rmtree("$tempdir/tarbackup2");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+
+	mkdir "$tempdir/$superlongname";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc3 LOCATION '$tempdir/$superlongname';");
+	$node->command_ok(
+		[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l3", '-Ft' , '-j 4'],
+		'pg_basebackup tar with long symlink target');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc3;");
+	rmtree("$tempdir/tarbackup_l3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxst", '-X', 'stream', '-Ft' , "-j 4"],
+	'pg_basebackup -X stream runs in tar mode');
+ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created");
+rmtree("$tempdir/backupxst");
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+#$node->command_checks_all(
+#	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt3", '-j 4'],
+#	1,
+#	[qr{^$}],
+#	[qr/^WARNING.*checksum verification failed/s],
+#	'pg_basebackup correctly report the total number of checksum mismatches');
+#rmtree("$tempdir/backup_corrupt3");
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.0 (Apple Git-122)

0003-pg_basebackup-changes-for-parallel-backup.patchapplication/octet-stream; name=0003-pg_basebackup-changes-for-parallel-backup.patchDownload
From 5c12e8fe83ba0fe2a7f24e1e84263fa112469390 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 14 Oct 2019 17:28:58 +0500
Subject: [PATCH 3/4] pg_basebackup changes for parallel backup.

---
 src/bin/pg_basebackup/pg_basebackup.c | 583 ++++++++++++++++++++++++--
 1 file changed, 548 insertions(+), 35 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 55ef13926d..311c1f94ca 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -41,6 +41,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -57,6 +58,37 @@ typedef struct TablespaceList
 	TablespaceListCell *tail;
 } TablespaceList;
 
+typedef struct
+{
+	char		name[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
+typedef struct
+{
+	Oid			tblspcOid;
+	char	   *tablespace;	/* tablespace name or NULL if 'base' tablespace */
+	int			numFiles;		/* number of files */
+	BackupFile *backupFiles; /* list of files in tablespace */
+} TablespaceInfo;
+
+typedef struct
+{
+	int 	tablespacecount;
+	int		numWorkers;
+
+	char	xlogstart[64];
+	char   *backup_label;
+	char   *tablespace_map;
+
+	TablespaceInfo *tsInfo;
+	SimpleStringList **worker_files;
+} BackupInfo;
+
+static BackupInfo *backupInfo = NULL;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -110,6 +142,10 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+static SimpleOidList workerspid = {NULL, NULL};
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -141,7 +177,7 @@ static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
 
-static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
+static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum, int worker);
 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
 
@@ -151,6 +187,16 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupEnd(void);
+static void GetBackupFilesList(PGconn *conn, BackupInfo *binfo);
+static int	ReceiveFiles(BackupInfo *backupInfo, int worker);
+static int	compareFileSize(const void *a, const void *b);
+static void create_workers_and_fetch(BackupInfo *backupInfo);
+static void read_label_tblspcmap(PGconn *conn, char **backup_label, char **tablespace_map);
+static void create_backup_dirs(bool basetablespace, char *tablespace, char *name);
+static void writefile(char *path, char *buf);
+static int	simple_list_length(SimpleStringList *list);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -349,6 +395,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -921,7 +968,7 @@ writeTarData(
  * No attempt to inspect or validate the contents of the file is done.
  */
 static void
-ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
+ReceiveTarFile(PGconn *conn, PGresult *res, int rownum, int worker)
 {
 	char		filename[MAXPGPATH];
 	char	   *copybuf = NULL;
@@ -978,7 +1025,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 #ifdef HAVE_LIBZ
 			if (compresslevel != 0)
 			{
-				snprintf(filename, sizeof(filename), "%s/base.tar.gz", basedir);
+				if (numWorkers > 1)
+					snprintf(filename, sizeof(filename), "%s/base.%d.tar.gz", basedir, worker);
+				else
+					snprintf(filename, sizeof(filename), "%s/base.tar.gz", basedir);
 				ztarfile = gzopen(filename, "wb");
 				if (gzsetparams(ztarfile, compresslevel,
 								Z_DEFAULT_STRATEGY) != Z_OK)
@@ -991,7 +1041,10 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			else
 #endif
 			{
-				snprintf(filename, sizeof(filename), "%s/base.tar", basedir);
+				if (numWorkers > 1)
+					snprintf(filename, sizeof(filename), "%s/base.%d.tar", basedir, worker);
+				else
+					snprintf(filename, sizeof(filename), "%s/base.tar", basedir);
 				tarfile = fopen(filename, "wb");
 			}
 		}
@@ -1004,8 +1057,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 #ifdef HAVE_LIBZ
 		if (compresslevel != 0)
 		{
-			snprintf(filename, sizeof(filename), "%s/%s.tar.gz", basedir,
-					 PQgetvalue(res, rownum, 0));
+			if (numWorkers > 1)
+				snprintf(filename, sizeof(filename), "%s/%s.%d.tar.gz", basedir,
+						 PQgetvalue(res, rownum, 0), worker);
+			else
+				snprintf(filename, sizeof(filename), "%s/%s.tar.gz", basedir,
+						 PQgetvalue(res, rownum, 0));
 			ztarfile = gzopen(filename, "wb");
 			if (gzsetparams(ztarfile, compresslevel,
 							Z_DEFAULT_STRATEGY) != Z_OK)
@@ -1018,8 +1075,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		else
 #endif
 		{
-			snprintf(filename, sizeof(filename), "%s/%s.tar", basedir,
-					 PQgetvalue(res, rownum, 0));
+			if (numWorkers > 1)
+				snprintf(filename, sizeof(filename), "%s/%s.%d.tar", basedir,
+						 PQgetvalue(res, rownum, 0), worker);
+			else
+				snprintf(filename, sizeof(filename), "%s/%s.tar", basedir,
+						 PQgetvalue(res, rownum, 0));
 			tarfile = fopen(filename, "wb");
 		}
 	}
@@ -1082,6 +1143,45 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 
 			MemSet(zerobuf, 0, sizeof(zerobuf));
 
+			if (numWorkers > 1 && basetablespace && worker == 0)
+			{
+				char		header[512];
+				int			padding;
+				int			len;
+
+				/* add backup_label and tablespace_map files to the tar */
+				len = strlen(backupInfo->backup_label);
+				tarCreateHeader(header,
+								"backup_label",
+								NULL,
+								len,
+								pg_file_create_mode, 04000, 02000,
+								time(NULL));
+
+				padding = ((len + 511) & ~511) - len;
+				WRITE_TAR_DATA(header, sizeof(header));
+				WRITE_TAR_DATA(backupInfo->backup_label, len);
+				if (padding)
+					WRITE_TAR_DATA(zerobuf, padding);
+
+				if (backupInfo->tablespace_map)
+				{
+					len = strlen(backupInfo->tablespace_map);
+					tarCreateHeader(header,
+									"tablespace_map",
+									NULL,
+									len,
+									pg_file_create_mode, 04000, 02000,
+									time(NULL));
+
+					padding = ((len + 511) & ~511) - len;
+					WRITE_TAR_DATA(header, sizeof(header));
+					WRITE_TAR_DATA(backupInfo->tablespace_map, len);
+					if (padding)
+						WRITE_TAR_DATA(zerobuf, padding);
+				}
+			}
+
 			if (basetablespace && writerecoveryconf)
 			{
 				char		header[512];
@@ -1475,6 +1575,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 			 */
 			snprintf(filename, sizeof(filename), "%s/%s", current_path,
 					 copybuf);
+
 			if (filename[strlen(filename) - 1] == '/')
 			{
 				/*
@@ -1486,21 +1587,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * Directory
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
+
+					/*
+					 * In parallel mode, we create directories before fetching
+					 * files so its Ok if a directory already exist.
+					 */
 					if (mkdir(filename, pg_dir_create_mode) != 0)
 					{
-						/*
-						 * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
-						 * clusters) will have been created by the wal
-						 * receiver process. Also, when the WAL directory
-						 * location was specified, pg_wal (or pg_xlog) has
-						 * already been created as a symbolic link before
-						 * starting the actual backup. So just ignore creation
-						 * failures on related directories.
-						 */
-						if (!((pg_str_endswith(filename, "/pg_wal") ||
-							   pg_str_endswith(filename, "/pg_xlog") ||
-							   pg_str_endswith(filename, "/archive_status")) &&
-							  errno == EEXIST))
+						if (errno != EEXIST)
 						{
 							pg_log_error("could not create directory \"%s\": %m",
 										 filename);
@@ -1528,8 +1622,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * can map them too.)
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
-
 					mapped_tblspc_path = get_tablespace_mapping(&copybuf[157]);
+
 					if (symlink(mapped_tblspc_path, filename) != 0)
 					{
 						pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
@@ -1716,7 +1810,8 @@ BaseBackup(void)
 	}
 
 	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+		psprintf("%s LABEL '%s' %s %s %s %s %s %s %s",
+				 (numWorkers > 1) ? "START_BACKUP" : "BASE_BACKUP",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
 				 includewal == FETCH_WAL ? "WAL" : "",
@@ -1774,7 +1869,7 @@ BaseBackup(void)
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1830,20 +1925,62 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		backupInfo = palloc0(sizeof(BackupInfo));
+
+		backupInfo->tablespacecount = tablespacecount;
+		backupInfo->numWorkers = numWorkers;
+		strlcpy(backupInfo->xlogstart, xlogstart, sizeof(backupInfo->xlogstart));
+		read_label_tblspcmap(conn, &backupInfo->backup_label, &backupInfo->tablespace_map);
+
+		/* retrive backup files from server. **/
+		GetBackupFilesList(conn, backupInfo);
+
+		/*
+		 * add backup_label in backup, (for tar format, ReceiveTarFile() will
+		 * takecare of it).
+		 */
+		if (format == 'p')
+			writefile("backup_label", backupInfo->backup_label);
+
+		/*
+		 * The backup files list is already in descending order, distribute it
+		 * to workers.
+		 */
+		backupInfo->worker_files = palloc0(sizeof(SimpleStringList) * tablespacecount);
+		for (i = 0; i < backupInfo->tablespacecount; i++)
+		{
+			TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+
+			backupInfo->worker_files[i] = palloc0(sizeof(SimpleStringList) * numWorkers);
+			for (int j = 0; j < curTsInfo->numFiles; j++)
+			{
+				simple_string_list_append(&backupInfo->worker_files[i][j % numWorkers],
+										  curTsInfo->backupFiles[j].name);
+			}
+		}
+
+		create_workers_and_fetch(backupInfo);
+		ParallelBackupEnd();
+	}
+	else
+	{
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i, 0);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+	}
 
 	if (showprogress)
 	{
-		progress_report(PQntuples(res), NULL, true);
+		progress_report(PQntuples(tablespacehdr), NULL, true);
 		if (isatty(fileno(stderr)))
 			fprintf(stderr, "\n");	/* Need to move to next line */
 	}
@@ -2043,6 +2180,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2070,7 +2208,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2211,6 +2349,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2325,6 +2466,14 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2397,3 +2546,367 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+static void
+ParallelBackupEnd(void)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP LABEL '%s' %s %s",
+					   backupInfo->backup_label,
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	if (format == 't')
+		ReceiveTarFile(conn, res, tablespacecount, numWorkers);
+	else
+		ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+
+	PQclear(res);
+}
+
+static void
+GetBackupFilesList(PGconn *conn, BackupInfo *backupInfo)
+{
+	int			i;
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	backupInfo->tsInfo = palloc0(sizeof(TablespaceInfo) * backupInfo->tablespacecount);
+	TablespaceInfo *tsInfo = backupInfo->tsInfo;
+
+	/*
+	 * Get list of files.
+	 */
+	basebkp = psprintf("SEND_FILE_LIST %s",
+					   format == 't' ? "TABLESPACE_MAP" : "");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SEND_FILE_LIST", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * The list of files is grouped by tablespaces, and we want to fetch them
+	 * in the same order.
+	 */
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		bool		basetablespace;
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tsInfo[i].tblspcOid = atol(PQgetvalue(tablespacehdr, i, 0));
+		tsInfo[i].tablespace = PQgetvalue(tablespacehdr, i, 1);
+		tsInfo[i].numFiles = PQntuples(res);
+		tsInfo[i].backupFiles =
+			palloc0(sizeof(BackupFile) * tsInfo[i].numFiles);
+
+		for (int j = 0; j < tsInfo[i].numFiles; j++)
+		{
+			char	   *name = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+				create_backup_dirs(basetablespace, tsInfo[i].tablespace, name);
+
+			strlcpy(tsInfo[i].backupFiles[j].name, name, MAXPGPATH);
+			tsInfo[i].backupFiles[j].type = type;
+			tsInfo[i].backupFiles[j].size = size;
+			tsInfo[i].backupFiles[j].mtime = mtime;
+		}
+
+		/* sort files in descending order, based on size */
+		qsort(tsInfo[i].backupFiles, tsInfo[i].numFiles,
+			  sizeof(BackupFile), &compareFileSize);
+		PQclear(res);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+}
+
+static int
+ReceiveFiles(BackupInfo *backupInfo, int worker)
+{
+	SimpleStringListCell *cell;
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn;
+	int			i;
+
+	worker_conn = GetConnection();
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+		SimpleStringList *files = &backupInfo->worker_files[i][worker];
+		PQExpBuffer buf = createPQExpBuffer();
+
+		if (simple_list_length(files) <= 0)
+			continue;
+
+
+		/*
+		 * build query in form of: SEND_FILES_CONTENT ('base/1/1245/32683',
+		 * 'base/1/1245/32683', ...) [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_FILES_CONTENT (");
+		for (cell = files->head; cell; cell = cell->next)
+		{
+			if (cell != files->tail)
+				appendPQExpBuffer(buf, "'%s' ,", cell->val);
+			else
+				appendPQExpBuffer(buf, "'%s'", cell->val);
+		}
+		appendPQExpBufferStr(buf, ")");
+
+		/*
+		 * Add backup options to the command. we are reusing the LABEL here to
+		 * keep the original tablespace path on the server.
+		 */
+		appendPQExpBuffer(buf, " LABEL '%s' LSN '%s' %s %s",
+						  curTsInfo->tablespace,
+						  backupInfo->xlogstart,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+
+		destroyPQExpBuffer(buf);
+		if (format == 't')
+			ReceiveTarFile(worker_conn, tablespacehdr, i, worker);
+		else
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, i);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	PQfinish(worker_conn);
+
+	return 0;
+}
+
+/* qsort comparator for BackupFile (sort descending order)  */
+static int
+compareFileSize(const void *a, const void *b)
+{
+	const		BackupFile *v1 = (BackupFile *) a;
+	const		BackupFile *v2 = (BackupFile *) b;
+
+	if (v1->size > v2->size)
+		return -1;
+	if (v1->size < v2->size)
+		return 1;
+
+	return 0;
+}
+
+static void
+create_workers_and_fetch(BackupInfo *backupInfo)
+{
+	int			status;
+	int			pid,
+				i;
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		pid = fork();
+		if (pid == 0)
+		{
+			/* in child process */
+			_exit(ReceiveFiles(backupInfo, i));
+		}
+		else if (pid < 0)
+		{
+			pg_log_error("could not create backup worker: %m");
+			exit(1);
+		}
+
+		simple_oid_list_append(&workerspid, pid);
+		if (verbose)
+			pg_log_info("backup worker (%d) created", pid);
+
+		/*
+		 * Else we are in the parent process and all is well.
+		 */
+	}
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		pid = waitpid(-1, &status, 0);
+
+		if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_FAILURE)
+		{
+			SimpleOidListCell *cell;
+
+			pg_log_error("backup worker (%d) failed with code %d", pid, WEXITSTATUS(status));
+
+			/* error. kill other workers and exit. */
+			for (cell = workerspid.head; cell; cell = cell->next)
+			{
+				if (pid != cell->val)
+				{
+					kill(cell->val, SIGTERM);
+					pg_log_error("backup worker killed %d", cell->val);
+				}
+			}
+
+			exit(1);
+		}
+	}
+}
+
+static void
+read_label_tblspcmap(PGconn *conn, char **backuplabel, char **tblspc_map)
+{
+	PGresult   *res = NULL;
+
+	Assert(backuplabel != NULL);
+	Assert(tblspc_map != NULL);
+
+	/*
+	 * Get Backup label and tablespace map data.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) < 1)
+	{
+		pg_log_error("no data returned from server");
+		exit(1);
+	}
+
+	*backuplabel = PQgetvalue(res, 0, 0);	/* backup_label */
+	if (!PQgetisnull(res, 0, 1))
+		*tblspc_map = PQgetvalue(res, 0, 1);	/* tablespae_map */
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	PQclear(res);
+}
+
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char	dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+static void
+writefile(char *path, char *buf)
+{
+	FILE   *f;
+	char	pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
+
+static int
+simple_list_length(SimpleStringList *list)
+{
+	int			len = 0;
+	SimpleStringListCell *cell;
+
+	for (cell = list->head; cell; cell = cell->next, len++)
+		;
+
+	return len;
+}
-- 
2.21.0 (Apple Git-122)

#24Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Asif Rehman (#23)
Re: WIP/PoC for parallel backup

On Thu, Oct 17, 2019 at 10:51 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

Attached are the updated patches.

I had a quick look over these changes and they look good overall.
However, here are my few review comments I caught while glancing the patches
0002 and 0003.

--- 0002 patch

1.
Can lsn option be renamed to start-wal-location? This will be more clear
too.

2.
+typedef struct
+{
+    char        name[MAXPGPATH];
+    char        type;
+    int32        size;
+    time_t        mtime;
+} BackupFile;

I think it will be good if we keep this structure in a common place so that
the client can also use it.

3.
+ SEND_FILE_LIST,
+ SEND_FILES_CONTENT,
Can above two commands renamed to SEND_BACKUP_MANIFEST and SEND_BACKUP_FILE
respectively?
The reason behind the first name change is, we are not getting only file
lists
here instead we are getting a few more details with that too. And for
others,
it will be inline with START_BACKUP/STOP_BACKUP/SEND_BACKUP_MANIFEST.

4.
Typos:
non-exlusive => non-exclusive
retured => returned
optionaly => optionally
nessery => necessary
totoal => total

--- 0003 patch
1.
+static int
+simple_list_length(SimpleStringList *list)
+{
+    int            len = 0;
+    SimpleStringListCell *cell;
+
+    for (cell = list->head; cell; cell = cell->next, len++)
+        ;
+
+    return len;
+}

I think it will be good if it goes to simple_list.c. That will help in other
usages as well.

2.
Please revert these unnecessary changes:

@@ -1475,6 +1575,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res,
int rownum)
*/
snprintf(filename, sizeof(filename), "%s/%s", current_path,
copybuf);
+
if (filename[strlen(filename) - 1] == '/')
{
/*

@@ -1528,8 +1622,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res,
int rownum)
* can map them too.)
*/
filename[strlen(filename) - 1] = '\0'; /* Remove
trailing slash */
-
mapped_tblspc_path =
get_tablespace_mapping(&copybuf[157]);
+
if (symlink(mapped_tblspc_path, filename) != 0)
{
pg_log_error("could not create symbolic link from
\"%s\" to \"%s\": %m",

3.
Typos:
retrive => retrieve
takecare => take care
tablespae => tablespace

4.
ParallelBackupEnd() function does not do anything for parallelism. Will it
be
better to just rename it as EndBackup()?

5.
To pass a tablespace path to the server in SEND_FILES_CONTENT, you are
reusing
a LABEL option, that seems odd. How about adding a new option for that?

6.
It will be good if we have some comments explaining what the function is
actually doing in its prologue. For functions like:
GetBackupFilesList()
ReceiveFiles()
create_workers_and_fetch()

Thanks

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

#25Ibrar Ahmed
ibrar.ahmad@gmail.com
In reply to: Jeevan Chalke (#24)
Re: WIP/PoC for parallel backup

On Fri, Oct 18, 2019 at 4:12 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

On Thu, Oct 17, 2019 at 10:51 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Attached are the updated patches.

I had a quick look over these changes and they look good overall.
However, here are my few review comments I caught while glancing the
patches
0002 and 0003.

--- 0002 patch

1.
Can lsn option be renamed to start-wal-location? This will be more clear
too.

2.
+typedef struct
+{
+    char        name[MAXPGPATH];
+    char        type;
+    int32        size;
+    time_t        mtime;
+} BackupFile;

I think it will be good if we keep this structure in a common place so that
the client can also use it.

3.
+ SEND_FILE_LIST,
+ SEND_FILES_CONTENT,
Can above two commands renamed to SEND_BACKUP_MANIFEST and SEND_BACKUP_FILE
respectively?
The reason behind the first name change is, we are not getting only file
lists
here instead we are getting a few more details with that too. And for
others,
it will be inline with START_BACKUP/STOP_BACKUP/SEND_BACKUP_MANIFEST.

4.
Typos:
non-exlusive => non-exclusive
retured => returned
optionaly => optionally
nessery => necessary
totoal => total

--- 0003 patch
1.
+static int
+simple_list_length(SimpleStringList *list)
+{
+    int            len = 0;
+    SimpleStringListCell *cell;
+
+    for (cell = list->head; cell; cell = cell->next, len++)
+        ;
+
+    return len;
+}

I think it will be good if it goes to simple_list.c. That will help in
other
usages as well.

2.
Please revert these unnecessary changes:

@@ -1475,6 +1575,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res,
int rownum)
*/
snprintf(filename, sizeof(filename), "%s/%s", current_path,
copybuf);
+
if (filename[strlen(filename) - 1] == '/')
{
/*

@@ -1528,8 +1622,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res,
int rownum)
* can map them too.)
*/
filename[strlen(filename) - 1] = '\0'; /* Remove
trailing slash */
-
mapped_tblspc_path =
get_tablespace_mapping(&copybuf[157]);
+
if (symlink(mapped_tblspc_path, filename) != 0)
{
pg_log_error("could not create symbolic link from
\"%s\" to \"%s\": %m",

3.
Typos:
retrive => retrieve
takecare => take care
tablespae => tablespace

4.
ParallelBackupEnd() function does not do anything for parallelism. Will it
be
better to just rename it as EndBackup()?

5.
To pass a tablespace path to the server in SEND_FILES_CONTENT, you are
reusing
a LABEL option, that seems odd. How about adding a new option for that?

6.
It will be good if we have some comments explaining what the function is
actually doing in its prologue. For functions like:
GetBackupFilesList()
ReceiveFiles()
create_workers_and_fetch()

Thanks

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

I had a detailed discussion with Robert Haas at PostgreConf Europe about
parallel backup.
We discussed the current state of the patch and what needs to be done to
get the patch committed.

- The current patch uses a process to implement parallelism. There are many
reasons we need to use threads instead of processes. To start with, as this
is a client utility it makes
more sense to use threads. The data needs to be shared amongst different
threads and the main process,
handling that is simpler as compared to interprocess communication.

- Fetching a single file or multiple files was also discussed. We concluded
in our discussion that we
need to benchmark to see if disk I/O is a bottleneck or not and if parallel
writing gives us
any benefit. This benchmark needs to be done on different hardware and
different
network to identify which are the real bottlenecks. In general, we agreed
that we could start with fetching
one file at a time but that will be revisited after the benchmarks are done.

- There is also an ongoing debate in this thread that we should have one
single tar file for all files or one
TAR file per thread. I really want to have a single tar file because the
main purpose of the TAR file is to
reduce the management of multiple files, but in case of one file per
thread, we end up with many tar
files. Therefore we need to have one master thread which is responsible for
writing on tar file and all
the other threads will receive the data from the network and stream to the
master thread. This also
supports the idea of using a thread-based model rather than a process-based
approach because it
requires too much data sharing between processes. If we cannot achieve
this, then we can disable the
TAR option for parallel backup in the first version.

- In the case of data sharing, we need to try to avoid unnecessary locking
and more suitable algorithm to
solve the reader-writer problem is required.

--
Ibrar Ahmed

#26Asif Rehman
asifr.rehman@gmail.com
In reply to: Ibrar Ahmed (#25)
Re: WIP/PoC for parallel backup

On Thu, Oct 24, 2019 at 3:21 PM Ibrar Ahmed <ibrar.ahmad@gmail.com> wrote:

On Fri, Oct 18, 2019 at 4:12 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

On Thu, Oct 17, 2019 at 10:51 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Attached are the updated patches.

I had a quick look over these changes and they look good overall.
However, here are my few review comments I caught while glancing the
patches
0002 and 0003.

--- 0002 patch

1.
Can lsn option be renamed to start-wal-location? This will be more clear
too.

2.
+typedef struct
+{
+    char        name[MAXPGPATH];
+    char        type;
+    int32        size;
+    time_t        mtime;
+} BackupFile;

I think it will be good if we keep this structure in a common place so
that
the client can also use it.

3.
+ SEND_FILE_LIST,
+ SEND_FILES_CONTENT,
Can above two commands renamed to SEND_BACKUP_MANIFEST and
SEND_BACKUP_FILE
respectively?
The reason behind the first name change is, we are not getting only file
lists
here instead we are getting a few more details with that too. And for
others,
it will be inline with START_BACKUP/STOP_BACKUP/SEND_BACKUP_MANIFEST.

4.
Typos:
non-exlusive => non-exclusive
retured => returned
optionaly => optionally
nessery => necessary
totoal => total

--- 0003 patch
1.
+static int
+simple_list_length(SimpleStringList *list)
+{
+    int            len = 0;
+    SimpleStringListCell *cell;
+
+    for (cell = list->head; cell; cell = cell->next, len++)
+        ;
+
+    return len;
+}

I think it will be good if it goes to simple_list.c. That will help in
other
usages as well.

2.
Please revert these unnecessary changes:

@@ -1475,6 +1575,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult
*res, int rownum)
*/
snprintf(filename, sizeof(filename), "%s/%s", current_path,
copybuf);
+
if (filename[strlen(filename) - 1] == '/')
{
/*

@@ -1528,8 +1622,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult
*res, int rownum)
* can map them too.)
*/
filename[strlen(filename) - 1] = '\0'; /* Remove
trailing slash */
-
mapped_tblspc_path =
get_tablespace_mapping(&copybuf[157]);
+
if (symlink(mapped_tblspc_path, filename) != 0)
{
pg_log_error("could not create symbolic link
from \"%s\" to \"%s\": %m",

3.
Typos:
retrive => retrieve
takecare => take care
tablespae => tablespace

4.
ParallelBackupEnd() function does not do anything for parallelism. Will
it be
better to just rename it as EndBackup()?

5.
To pass a tablespace path to the server in SEND_FILES_CONTENT, you are
reusing
a LABEL option, that seems odd. How about adding a new option for that?

6.
It will be good if we have some comments explaining what the function is
actually doing in its prologue. For functions like:
GetBackupFilesList()
ReceiveFiles()
create_workers_and_fetch()

Thanks

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

I had a detailed discussion with Robert Haas at PostgreConf Europe about
parallel backup.
We discussed the current state of the patch and what needs to be done to
get the patch committed.

- The current patch uses a process to implement parallelism. There are many
reasons we need to use threads instead of processes. To start with, as
this is a client utility it makes
more sense to use threads. The data needs to be shared amongst different
threads and the main process,
handling that is simpler as compared to interprocess communication.

Yes I agree. I have already converted the code to use threads instead of
processes. This avoids the overhead
of interprocess communication.

With a single file fetching strategy, this requires communication between
competing threads/processes. To handle
that in a multiprocess application, it requires IPC. The current approach
of multiple threads instead of processes
avoids this overhead.

- Fetching a single file or multiple files was also discussed. We
concluded in our discussion that we
need to benchmark to see if disk I/O is a bottleneck or not and if
parallel writing gives us
any benefit. This benchmark needs to be done on different hardware and
different
network to identify which are the real bottlenecks. In general, we agreed
that we could start with fetching
one file at a time but that will be revisited after the benchmarks are
done.

I'll share the updated patch in the next couple of days. After that, I'll
work on benchmarking that in
different environments that I have.

- There is also an ongoing debate in this thread that we should have one
single tar file for all files or one
TAR file per thread. I really want to have a single tar file because the
main purpose of the TAR file is to
reduce the management of multiple files, but in case of one file per
thread, we end up with many tar
files. Therefore we need to have one master thread which is responsible
for writing on tar file and all
the other threads will receive the data from the network and stream to the
master thread. This also
supports the idea of using a thread-based model rather than a
process-based approach because it
requires too much data sharing between processes. If we cannot achieve
this, then we can disable the
TAR option for parallel backup in the first version.

I am in favour of disabling the tar format for the first version of
parallel backup.

- In the case of data sharing, we need to try to avoid unnecessary locking
and more suitable algorithm to
solve the reader-writer problem is required.

--
Ibrar Ahmed

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#27Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#26)
5 attachment(s)
Re: WIP/PoC for parallel backup

On Thu, Oct 24, 2019 at 4:24 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Thu, Oct 24, 2019 at 3:21 PM Ibrar Ahmed <ibrar.ahmad@gmail.com> wrote:

On Fri, Oct 18, 2019 at 4:12 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

On Thu, Oct 17, 2019 at 10:51 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Attached are the updated patches.

I had a quick look over these changes and they look good overall.
However, here are my few review comments I caught while glancing the
patches
0002 and 0003.

--- 0002 patch

1.
Can lsn option be renamed to start-wal-location? This will be more clear
too.

2.
+typedef struct
+{
+    char        name[MAXPGPATH];
+    char        type;
+    int32        size;
+    time_t        mtime;
+} BackupFile;

I think it will be good if we keep this structure in a common place so
that
the client can also use it.

3.
+ SEND_FILE_LIST,
+ SEND_FILES_CONTENT,
Can above two commands renamed to SEND_BACKUP_MANIFEST and
SEND_BACKUP_FILE
respectively?
The reason behind the first name change is, we are not getting only file
lists
here instead we are getting a few more details with that too. And for
others,
it will be inline with START_BACKUP/STOP_BACKUP/SEND_BACKUP_MANIFEST.

4.
Typos:
non-exlusive => non-exclusive
retured => returned
optionaly => optionally
nessery => necessary
totoal => total

--- 0003 patch
1.
+static int
+simple_list_length(SimpleStringList *list)
+{
+    int            len = 0;
+    SimpleStringListCell *cell;
+
+    for (cell = list->head; cell; cell = cell->next, len++)
+        ;
+
+    return len;
+}

I think it will be good if it goes to simple_list.c. That will help in
other
usages as well.

2.
Please revert these unnecessary changes:

@@ -1475,6 +1575,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult
*res, int rownum)
*/
snprintf(filename, sizeof(filename), "%s/%s", current_path,
copybuf);
+
if (filename[strlen(filename) - 1] == '/')
{
/*

@@ -1528,8 +1622,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult
*res, int rownum)
* can map them too.)
*/
filename[strlen(filename) - 1] = '\0'; /* Remove
trailing slash */
-
mapped_tblspc_path =
get_tablespace_mapping(&copybuf[157]);
+
if (symlink(mapped_tblspc_path, filename) != 0)
{
pg_log_error("could not create symbolic link
from \"%s\" to \"%s\": %m",

3.
Typos:
retrive => retrieve
takecare => take care
tablespae => tablespace

4.
ParallelBackupEnd() function does not do anything for parallelism. Will
it be
better to just rename it as EndBackup()?

5.
To pass a tablespace path to the server in SEND_FILES_CONTENT, you are
reusing
a LABEL option, that seems odd. How about adding a new option for that?

6.
It will be good if we have some comments explaining what the function is
actually doing in its prologue. For functions like:
GetBackupFilesList()
ReceiveFiles()
create_workers_and_fetch()

Thanks

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

I had a detailed discussion with Robert Haas at PostgreConf Europe about
parallel backup.
We discussed the current state of the patch and what needs to be done to
get the patch committed.

- The current patch uses a process to implement parallelism. There are
many
reasons we need to use threads instead of processes. To start with, as
this is a client utility it makes
more sense to use threads. The data needs to be shared amongst different
threads and the main process,
handling that is simpler as compared to interprocess communication.

Yes I agree. I have already converted the code to use threads instead of
processes. This avoids the overhead
of interprocess communication.

With a single file fetching strategy, this requires communication between
competing threads/processes. To handle
that in a multiprocess application, it requires IPC. The current approach
of multiple threads instead of processes
avoids this overhead.

- Fetching a single file or multiple files was also discussed. We
concluded in our discussion that we
need to benchmark to see if disk I/O is a bottleneck or not and if
parallel writing gives us
any benefit. This benchmark needs to be done on different hardware and
different
network to identify which are the real bottlenecks. In general, we agreed
that we could start with fetching
one file at a time but that will be revisited after the benchmarks are
done.

I'll share the updated patch in the next couple of days. After that, I'll
work on benchmarking that in
different environments that I have.

- There is also an ongoing debate in this thread that we should have one
single tar file for all files or one
TAR file per thread. I really want to have a single tar file because the
main purpose of the TAR file is to
reduce the management of multiple files, but in case of one file per
thread, we end up with many tar
files. Therefore we need to have one master thread which is responsible
for writing on tar file and all
the other threads will receive the data from the network and stream to
the master thread. This also
supports the idea of using a thread-based model rather than a
process-based approach because it
requires too much data sharing between processes. If we cannot achieve
this, then we can disable the
TAR option for parallel backup in the first version.

I am in favour of disabling the tar format for the first version of
parallel backup.

- In the case of data sharing, we need to try to avoid unnecessary
locking and more suitable algorithm to
solve the reader-writer problem is required.

--
Ibrar Ahmed

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

I have updated the patch to include the changes suggested by Jeevan. This
patch also implements the thread workers instead of
processes and fetches a single file at a time. The tar format has been
disabled for first version of parallel backup.

Conversion from the previous process based application to the current
thread based one required slight modification in data structure,
addition of a few new functions and progress reporting functionality.

The core data structure remains in tact where table space based file
listing is maintained, however, we are now maintaining a list of all
files (maintaining pointers to FileInfo structure; so no duplication of
data), so that we can sequentially access these without adding too
much processing in critical section. The current scope of the critical
section for thread workers is limited to incrementing the file index
within the list of files.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0005-parallel-backup-testcase_v3.patchapplication/octet-stream; name=0005-parallel-backup-testcase_v3.patchDownload
From 30e3c102ad5782d3c814455824be9a53c93c3e9a Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 5/5] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 567 ++++++++++++++++++
 1 file changed, 567 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..2dac7bc82a
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,567 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 95;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# Tar format doesn't support filenames longer than 100 bytes.
+#my $superlongname = "superlongname_" . ("x" x 100);
+#my $superlongpath = "$pgdata/$superlongname";
+#
+#open my $file, '>', "$superlongpath"
+#  or die "unable to create file $superlongpath";
+#close $file;
+#$node->command_fails(
+#	[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft', "-j 4" ],
+#	'pg_basebackup tar with long name fails');
+#unlink "$pgdata/$superlongname";
+my $file;
+
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+#	# Create a temporary directory in the system location and symlink it
+#	# to our physical temp location.  That way we can use shorter names
+#	# for the tablespace directories, which hopefully won't run afoul of
+#	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+#	$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/tarbackup2", '-Ft', "-j 4" ],
+#		'tar format with tablespaces');
+#	ok(-f "$tempdir/tarbackup2/base.0.tar", 'backup tar was created');
+#	my @tblspc_tars = glob "$tempdir/tarbackup2/[0-9]*.tar";
+#	is(scalar(@tblspc_tars), 1, 'one tablespace tar was created');
+#	rmtree("$tempdir/tarbackup2");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+
+#	mkdir "$tempdir/$superlongname";
+#	$node->safe_psql('postgres',
+#		"CREATE TABLESPACE tblspc3 LOCATION '$tempdir/$superlongname';");
+#	$node->command_ok(
+#		[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l3", '-Ft' , '-j 4'],
+#		'pg_basebackup tar with long symlink target');
+#	$node->safe_psql('postgres', "DROP TABLESPACE tblspc3;");
+#	rmtree("$tempdir/tarbackup_l3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+#$node->command_ok(
+#	[ 'pg_basebackup', '-D', "$tempdir/backupxst", '-X', 'stream', '-Ft' , "-j 4"],
+#	'pg_basebackup -X stream runs in tar mode');
+#ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created");
+#rmtree("$tempdir/backupxst");
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+#$node->command_checks_all(
+#	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt3", '-j 4'],
+#	1,
+#	[qr{^$}],
+#	[qr/^WARNING.*checksum verification failed/s],
+#	'pg_basebackup correctly report the total number of checksum mismatches');
+#rmtree("$tempdir/backup_corrupt3");
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.0 (Apple Git-122)

0003-add-exclusive-backup-option-in-parallel-backup_v3.patchapplication/octet-stream; name=0003-add-exclusive-backup-option-in-parallel-backup_v3.patchDownload
From bf494ca68028e22fdd8984170bc7c41801e4b82a Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 27 Oct 2019 23:27:03 +0500
Subject: [PATCH 3/5] add 'exclusive' backup option in parallel backup

---
 src/backend/replication/basebackup.c   | 99 ++++++++++++++++++++++++--
 src/backend/replication/repl_gram.y    |  6 ++
 src/backend/replication/repl_scanner.l |  1 +
 3 files changed, 99 insertions(+), 7 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 4a382c4558..1c657e247a 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -55,6 +55,7 @@ typedef struct
 	bool		sendtblspcmapfile;
 	const char *tablespace_path;
 	XLogRecPtr	wal_location;
+	bool		exclusive;
 } basebackup_options;
 
 typedef struct
@@ -104,6 +105,7 @@ static void StartBackup(basebackup_options *opt);
 static void StopBackup(basebackup_options *opt);
 static void SendBackupManifest(basebackup_options *opt);
 static void SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok);
+static char *readfile(const char *readfilename, bool missing_ok);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
@@ -256,7 +258,14 @@ static const char *const noChecksumFiles[] = {
 static void
 base_backup_cleanup(int code, Datum arg)
 {
-	do_pg_abort_backup();
+	bool exclusive = DatumGetBool(arg);
+
+	/*
+	 * do_pg_abort_backup is only for non-exclusive backups, exclusive backup
+	 * is terminated by calling pg_stop_backup().
+	 */
+	if (!exclusive)
+		do_pg_abort_backup();
 }
 
 /*
@@ -443,6 +452,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_noverify_checksums = false;
 	bool		o_tablespace_path = false;
 	bool		o_wal_location = false;
+	bool		o_exclusive = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -554,6 +564,16 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			opt->wal_location = pg_lsn_in_internal(wal_location, &have_error);
 			o_wal_location = true;
 		}
+		else if (strcmp(defel->defname, "exclusive") == 0)
+		{
+			if (o_exclusive)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			opt->exclusive = intVal(defel->arg);
+			o_exclusive = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -1944,7 +1964,7 @@ StartBackup(basebackup_options *opt)
 	total_checksum_failures = 0;
 
 	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
-								  labelfile, &tablespaces,
+								  opt->exclusive? NULL : labelfile, &tablespaces,
 								  tblspc_map_file,
 								  opt->progress, opt->sendtblspcmapfile);
 
@@ -1955,7 +1975,7 @@ StartBackup(basebackup_options *opt)
 	 * do_pg_stop_backup() should be inside the error cleanup block!
 	 */
 
-	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) BoolGetDatum(opt->exclusive));
 	{
 		tablespaceinfo *ti;
 
@@ -1984,6 +2004,25 @@ StartBackup(basebackup_options *opt)
 		/* Setup and activate network throttling, if client requested it */
 		setup_throttle(opt->maxrate);
 
+		/*
+		 * In exclusive mode, pg_start_backup creates backup_label and
+		 * tablespace_map files and does not return their contents in
+		 * *labelfile and *tblspcmapfile. So we read them from these files to
+		 * return to frontend.
+		 *
+		 * In non-exclusive mode, contents of these files are available in
+		 * *labelfile and *tblspcmapfile and are returned directly.
+		 */
+		if (opt->exclusive)
+		{
+			resetStringInfo(labelfile);
+			resetStringInfo(tblspc_map_file);
+
+			appendStringInfoString(labelfile, readfile(BACKUP_LABEL_FILE, false));
+			if (opt->sendtblspcmapfile)
+				appendStringInfoString(tblspc_map_file, readfile(TABLESPACE_MAP, false));
+		}
+
 		if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
 			!opt->sendtblspcmapfile)
 			tblspc_map_file = NULL;
@@ -1991,14 +2030,14 @@ StartBackup(basebackup_options *opt)
 		/* send backup_label and tablespace_map to frontend */
 		SendStartBackupResult(labelfile, tblspc_map_file);
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) BoolGetDatum(opt->exclusive));
 }
 
 /*
  * StopBackup() - ends an online backup
  *
  * The function is called at the end of an online backup. It sends out pg_control
- * file, optionaly WAL segments and ending WAL location.
+ * file, optionally WAL segments and ending WAL location.
  */
 static void
 StopBackup(basebackup_options *opt)
@@ -2009,7 +2048,7 @@ StopBackup(basebackup_options *opt)
 	StringInfoData buf;
 	char	   *labelfile = NULL;
 
-	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) BoolGetDatum(opt->exclusive));
 	{
 		/* Setup and activate network throttling, if client requested it */
 		setup_throttle(opt->maxrate);
@@ -2028,6 +2067,8 @@ StopBackup(basebackup_options *opt)
 		sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 
 		/* stop backup */
+		if (!opt->exclusive)
+			labelfile = (char *) opt->label;
 		endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
 
 		if (opt->includewal)
@@ -2036,7 +2077,7 @@ StopBackup(basebackup_options *opt)
 		pq_putemptymessage('c');	/* CopyDone */
 		SendXlogRecPtrResult(endptr, endtli);
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) BoolGetDatum(opt->exclusive));
 }
 
 /*
@@ -2271,3 +2312,47 @@ SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok)
 				 errmsg("checksum verification failure during base backup")));
 	}
 }
+
+static char *
+readfile(const char *readfilename, bool missing_ok)
+{
+	struct stat statbuf;
+	FILE	   *fp;
+	char	   *data;
+	int			r;
+
+	if (stat(readfilename, &statbuf))
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						readfilename)));
+	}
+
+	fp = AllocateFile(readfilename, "r");
+	if (!fp)
+	{
+		if (errno == ENOENT && missing_ok)
+			return NULL;
+
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not open file \"%s\": %m", readfilename)));
+	}
+
+	data = palloc(statbuf.st_size + 1);
+	r = fread(data, statbuf.st_size, 1, fp);
+	data[statbuf.st_size] = '\0';
+
+	/* Close the file */
+	if (r != 1 || ferror(fp) || FreeFile(fp))
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not read file \"%s\": %m",
+						readfilename)));
+
+	return data;
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index 9e2499814b..94c6aafbed 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -93,6 +93,7 @@ static SQLCmd *make_sqlcmd(void);
 %token K_STOP_BACKUP
 %token K_START_WAL_LOCATION
 %token K_TABLESPACE_PATH
+%token K_EXCLUSIVE
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
@@ -262,6 +263,11 @@ base_backup_opt:
 				  $$ = makeDefElem("tablespace_path",
 								   (Node *)makeString($2), -1);
 				}
+			| K_EXCLUSIVE
+				{
+				  $$ = makeDefElem("exclusive",
+								   (Node *)makeInteger(true), -1);
+				}
 			;
 
 backup_files:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 7a1bb54da8..ad0dd04cb1 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -113,6 +113,7 @@ SEND_BACKUP_FILES	{ return K_SEND_BACKUP_FILES; }
 STOP_BACKUP			{ return K_STOP_BACKUP; }
 START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
 TABLESPACE_PATH		{ return K_TABLESPACE_PATH; }
+EXCLUSIVE			{ return K_EXCLUSIVE; }
 
 
 ","				{ return ','; }
-- 
2.21.0 (Apple Git-122)

0004-pg_basebackup-changes-for-parallel-backup_v3.patchapplication/octet-stream; name=0004-pg_basebackup-changes-for-parallel-backup_v3.patchDownload
From 3ef5c3f40137ed15039f95d4e6e9487fa6edc3c7 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 14 Oct 2019 17:28:58 +0500
Subject: [PATCH 4/5] pg_basebackup changes for parallel backup.

---
 src/bin/pg_basebackup/pg_basebackup.c | 710 ++++++++++++++++++++++++--
 1 file changed, 672 insertions(+), 38 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index a9d162a7da..1dff398c11 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -19,6 +19,7 @@
 #include <sys/wait.h>
 #include <signal.h>
 #include <time.h>
+#include <pthread.h>
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -41,6 +42,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -57,6 +59,57 @@ typedef struct TablespaceList
 	TablespaceListCell *tail;
 } TablespaceList;
 
+typedef struct
+{
+	char		name[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+
+	int			tsIndex;	/* index of tsInfo this file belongs to. */
+} BackupFile;
+
+typedef struct
+{
+	Oid			tblspcOid;
+	char	   *tablespace;	 /* tablespace name or NULL if 'base' tablespace */
+	int			numFiles;	 /* number of files */
+	BackupFile *backupFiles; /* list of files in a tablespace */
+} TablespaceInfo;
+
+typedef struct
+{
+	int 	tablespacecount;
+	int		totalfiles;
+	int		numWorkers;
+
+	char	xlogstart[64];
+	char   *backup_label;
+	char   *tablespace_map;
+
+	TablespaceInfo *tsInfo;
+	BackupFile	  **files;		/* list of BackupFile pointers */
+	int				fileIndex;	/* index of file to be fetched */
+
+	PGconn	**workerConns;
+} BackupInfo;
+
+typedef struct
+{
+	BackupInfo *backupInfo;
+	uint64		bytesRead;
+
+	int			workerid;
+	pthread_t	worker;
+
+	bool	terminated;
+} WorkerState;
+
+BackupInfo *backupInfo = NULL;
+WorkerState *workers = NULL;
+
+static pthread_mutex_t fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -110,6 +163,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -140,9 +196,10 @@ static PQExpBuffer recoveryconfcontents = NULL;
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
+static void workers_progress_report(uint64 totalBytesRead, const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
-static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
+static int	ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
 
 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -151,6 +208,17 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupRun(BackupInfo *backupInfo);
+static void StopBackup(BackupInfo *backupInfo);
+static void GetBackupManifest(PGconn *conn, BackupInfo *backupInfo);
+static int GetBackupFile(WorkerState *wstate);
+static BackupFile *getNextFile(BackupInfo *backupInfo);
+static int	compareFileSize(const void *a, const void *b);
+static void read_label_tblspcmap(PGconn *conn, char **backup_label, char **tablespace_map);
+static void create_backup_dirs(bool basetablespace, char *tablespace, char *name);
+static void writefile(char *path, char *buf);
+static void *workerRun(void *arg);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -202,6 +270,17 @@ cleanup_directories_atexit(void)
 static void
 disconnect_atexit(void)
 {
+	/* close worker connections */
+	if (backupInfo && backupInfo->workerConns != NULL)
+	{
+		int i;
+		for (i = 0; i < numWorkers; i++)
+		{
+			if (backupInfo->workerConns[i] != NULL)
+				PQfinish(backupInfo->workerConns[i]);
+		}
+	}
+
 	if (conn != NULL)
 		PQfinish(conn);
 }
@@ -349,6 +428,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -695,6 +775,93 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 	}
 }
 
+/*
+ * Print a progress report of worker threads. If verbose output
+ * is enabled, also print the current file name.
+ *
+ * Progress report is written at maximum once per second, unless the
+ * force parameter is set to true.
+ */
+static void
+workers_progress_report(uint64 totalBytesRead, const char *filename, bool force)
+{
+	int			percent;
+	char		totalBytesRead_str[32];
+	char		totalsize_str[32];
+	pg_time_t	now;
+
+	if (!showprogress)
+		return;
+
+	now = time(NULL);
+	if (now == last_progress_report && !force)
+		return;					/* Max once per second */
+
+	last_progress_report = now;
+	percent = totalsize_kb ? (int) ((totalBytesRead / 1024) * 100 / totalsize_kb) : 0;
+
+	/*
+	 * Avoid overflowing past 100% or the full size. This may make the total
+	 * size number change as we approach the end of the backup (the estimate
+	 * will always be wrong if WAL is included), but that's better than having
+	 * the done column be bigger than the total.
+	 */
+	if (percent > 100)
+		percent = 100;
+	if (totalBytesRead / 1024 > totalsize_kb)
+		totalsize_kb = totalBytesRead / 1024;
+
+	/*
+	 * Separate step to keep platform-dependent format code out of
+	 * translatable strings.  And we only test for INT64_FORMAT availability
+	 * in snprintf, not fprintf.
+	 */
+	snprintf(totalBytesRead_str, sizeof(totalBytesRead_str), INT64_FORMAT,
+			 totalBytesRead / 1024);
+	snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
+
+#define VERBOSE_FILENAME_LENGTH 35
+
+	if (verbose)
+	{
+		if (!filename)
+
+			/*
+			 * No filename given, so clear the status line (used for last
+			 * call)
+			 */
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied %*s"),
+					(int) strlen(totalsize_str),
+					totalBytesRead_str, totalsize_str,
+					percent,
+					VERBOSE_FILENAME_LENGTH + 5, "");
+		else
+		{
+			bool		truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied, current file (%s%-*.*s)"),
+					(int) strlen(totalsize_str), totalBytesRead_str, totalsize_str,
+					percent,
+					/* Prefix with "..." if we do leading truncation */
+							truncate ? "..." : "",
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+					/* Truncate filename at beginning if it's too long */
+							truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+				(int) strlen(totalsize_str),
+				totalBytesRead_str, totalsize_str,
+				percent);
+	}
+
+	if (isatty(fileno(stderr)))
+		fprintf(stderr, "\r");
+	else
+		fprintf(stderr, "\n");
+}
 
 /*
  * Print a progress report based on the global variables. If verbose output
@@ -711,7 +878,7 @@ progress_report(int tablespacenum, const char *filename, bool force)
 	char		totalsize_str[32];
 	pg_time_t	now;
 
-	if (!showprogress)
+	if (!showprogress || numWorkers > 1)
 		return;
 
 	now = time(NULL);
@@ -1381,7 +1548,7 @@ get_tablespace_mapping(const char *dir)
  * specified directory. If it's for another tablespace, it will be restored
  * in the original or mapped directory.
  */
-static void
+static int
 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 {
 	char		current_path[MAXPGPATH];
@@ -1392,6 +1559,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	bool		basetablespace;
 	char	   *copybuf = NULL;
 	FILE	   *file = NULL;
+	int			readBytes = 0;
 
 	basetablespace = PQgetisnull(res, rownum, 0);
 	if (basetablespace)
@@ -1455,7 +1623,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("invalid tar block header size: %d", r);
 				exit(1);
 			}
-			totaldone += 512;
+			readBytes += 512;
 
 			current_len_left = read_tar_number(&copybuf[124], 12);
 
@@ -1486,21 +1654,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * Directory
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
+
+					/*
+					 * In parallel mode, we create directories before fetching
+					 * files so its Ok if a directory already exist.
+					 */
 					if (mkdir(filename, pg_dir_create_mode) != 0)
 					{
-						/*
-						 * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
-						 * clusters) will have been created by the wal
-						 * receiver process. Also, when the WAL directory
-						 * location was specified, pg_wal (or pg_xlog) has
-						 * already been created as a symbolic link before
-						 * starting the actual backup. So just ignore creation
-						 * failures on related directories.
-						 */
-						if (!((pg_str_endswith(filename, "/pg_wal") ||
-							   pg_str_endswith(filename, "/pg_xlog") ||
-							   pg_str_endswith(filename, "/archive_status")) &&
-							  errno == EEXIST))
+						if (errno != EEXIST)
 						{
 							pg_log_error("could not create directory \"%s\": %m",
 										 filename);
@@ -1585,7 +1746,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				 */
 				fclose(file);
 				file = NULL;
-				totaldone += r;
+				readBytes += r;
 				continue;
 			}
 
@@ -1594,7 +1755,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("could not write to file \"%s\": %m", filename);
 				exit(1);
 			}
-			totaldone += r;
+			readBytes += r;
+			totaldone = readBytes;
 			progress_report(rownum, filename, false);
 
 			current_len_left -= r;
@@ -1622,13 +1784,11 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	if (copybuf != NULL)
 		PQfreemem(copybuf);
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
-
 	/*
 	 * No data is synced here, everything is done for all tablespaces at the
 	 * end.
 	 */
+	return readBytes;
 }
 
 
@@ -1716,7 +1876,8 @@ BaseBackup(void)
 	}
 
 	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+		psprintf("%s LABEL '%s' %s %s %s %s %s %s %s",
+				 (numWorkers > 1) ? "START_BACKUP" : "BASE_BACKUP",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
 				 includewal == FETCH_WAL ? "WAL" : "",
@@ -1774,7 +1935,7 @@ BaseBackup(void)
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1830,24 +1991,74 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		int j = 0,
+			k = 0;
 
-	if (showprogress)
+		backupInfo = palloc0(sizeof(BackupInfo));
+		backupInfo->workerConns = (PGconn **) palloc0(sizeof(PGconn *) * numWorkers);
+		backupInfo->tablespacecount = tablespacecount;
+		backupInfo->numWorkers = numWorkers;
+		strlcpy(backupInfo->xlogstart, xlogstart, sizeof(backupInfo->xlogstart));
+
+		read_label_tblspcmap(conn, &backupInfo->backup_label, &backupInfo->tablespace_map);
+
+		/* retrieve backup manifest from the server. **/
+		GetBackupManifest(conn, backupInfo);
+
+		/*
+		 * add backup_label in backup, (for tar format, ReceiveTarFile() will
+		 * take care of it).
+		 */
+		if (format == 'p')
+			writefile("backup_label", backupInfo->backup_label);
+
+		/*
+		 * Flatten the file list to avoid unnecessary locks and enable the sequential
+		 * access to file list. (Creating an array of BackupFile structre pointers).
+		 */
+		backupInfo->files =
+			(BackupFile **) palloc0(sizeof(BackupFile *) * backupInfo->totalfiles);
+		for (i = 0; i < backupInfo->tablespacecount; i++)
+		{
+			TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+
+			for (j = 0; j < curTsInfo->numFiles; j++)
+			{
+				backupInfo->files[k] = &curTsInfo->backupFiles[j];
+				k++;
+			}
+		}
+
+		ParallelBackupRun(backupInfo);
+		StopBackup(backupInfo);
+	}
+	else
 	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+
+		if (showprogress)
+		{
+			progress_report(PQntuples(tablespacehdr), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
 	}
 
+	/* Write recovery contents */
+	if (format == 'p' && writerecoveryconf)
+		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
+
 	PQclear(res);
 
 	/*
@@ -2043,6 +2254,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2070,7 +2282,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2211,6 +2423,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2325,6 +2540,22 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (format != 'p' && numWorkers > 1)
+	{
+		pg_log_error("parallel jobs are only supported with 'plain' format");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2397,3 +2628,406 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+/*
+ * Thread worker
+ */
+static void *
+workerRun(void *arg)
+{
+	WorkerState *wstate = (WorkerState *) arg;
+
+	GetBackupFile(wstate);
+
+	wstate->terminated = true;
+	return NULL;
+}
+
+/*
+ * Runs the worker threads and updates progress until all workers have
+ * terminated/completed.
+ */
+static void
+ParallelBackupRun(BackupInfo *backupInfo)
+{
+	int		status,
+			i;
+	bool	threadsActive = true;
+	uint64	totalBytes = 0;
+
+	workers = (WorkerState *) palloc0(sizeof(WorkerState) * numWorkers);
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		WorkerState *worker = &workers[i];
+
+		worker->backupInfo = backupInfo;
+		worker->workerid = i;
+		worker->bytesRead = 0;
+		worker->terminated = false;
+
+		backupInfo->workerConns[i] = GetConnection();
+		status = pthread_create(&worker->worker, NULL, workerRun, worker);
+		if (status != 0)
+		{
+			pg_log_error("failed to create thread: %m");
+			exit(1);
+		}
+
+		if (verbose)
+			pg_log_info("backup worker (%d) created, %d", i, status);
+	}
+
+	/*
+	 * This is the main thread for updating progrsss. It waits for workers to
+	 * complete and gets updated status during every loop iteration.
+	 */
+	while(threadsActive)
+	{
+		char *filename = NULL;
+
+		threadsActive = false;
+		totalBytes = 0;
+
+		for (i = 0; i < numWorkers; i++)
+		{
+			WorkerState *worker = &workers[i];
+
+			totalBytes += worker->bytesRead;
+			threadsActive |= !worker->terminated;
+		}
+
+		if (backupInfo->fileIndex < backupInfo->totalfiles)
+			filename = backupInfo->files[backupInfo->fileIndex]->name;
+
+		workers_progress_report(totalBytes, filename, false);
+		pg_usleep(100000);
+	}
+
+	if (showprogress)
+	{
+		workers_progress_report(totalBytes, NULL, true);
+		if (isatty(fileno(stderr)))
+			fprintf(stderr, "\n");	/* Need to move to next line */
+	}
+}
+
+/*
+ * Take the system out of backup mode.
+ */
+static void
+StopBackup(BackupInfo *backupInfo)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP LABEL '%s' %s %s",
+					   backupInfo->backup_label,
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+	PQclear(res);
+}
+
+/*
+ * Retrive backup manifest from the server and populate TablespaceInfo struct
+ * to keep track of tablespaces and its files.
+ */
+static void
+GetBackupManifest(PGconn *conn, BackupInfo *backupInfo)
+{
+	int			i;
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	backupInfo->tsInfo = palloc0(sizeof(TablespaceInfo) * backupInfo->tablespacecount);
+	TablespaceInfo *tsInfo = backupInfo->tsInfo;
+
+	/*
+	 * Get list of files.
+	 */
+	basebkp = psprintf("SEND_BACKUP_MANIFEST %s",
+					   format == 't' ? "TABLESPACE_MAP" : "");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SEND_BACKUP_MANIFEST", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * The list of files is grouped by tablespaces, and we want to fetch them
+	 * in the same order.
+	 */
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		bool		basetablespace;
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tsInfo[i].tblspcOid = atol(PQgetvalue(tablespacehdr, i, 0));
+		tsInfo[i].tablespace = PQgetvalue(tablespacehdr, i, 1);
+		tsInfo[i].numFiles = PQntuples(res);
+		tsInfo[i].backupFiles = palloc0(sizeof(BackupFile) * tsInfo[i].numFiles);
+
+		/* keep count of all files in backup */
+		backupInfo->totalfiles += tsInfo[i].numFiles;
+
+		for (int j = 0; j < tsInfo[i].numFiles; j++)
+		{
+			char	   *name = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+				create_backup_dirs(basetablespace, tsInfo[i].tablespace, name);
+
+			strlcpy(tsInfo[i].backupFiles[j].name, name, MAXPGPATH);
+			tsInfo[i].backupFiles[j].type = type;
+			tsInfo[i].backupFiles[j].size = size;
+			tsInfo[i].backupFiles[j].mtime = mtime;
+			tsInfo[i].backupFiles[j].tsIndex = i;
+		}
+
+		/* sort files in descending order, based on size */
+		qsort(tsInfo[i].backupFiles, tsInfo[i].numFiles,
+			  sizeof(BackupFile), &compareFileSize);
+		PQclear(res);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+}
+
+/*
+ * Retrive and write backup file from the server. The file list is provided by
+ * worker state. It pulls a single file from this list and writes it to the
+ * backup directory.
+ */
+static int
+GetBackupFile(WorkerState *wstate)
+{
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn = NULL;
+	BackupFile *fetchFile = NULL;
+	BackupInfo *backupInfo = NULL;
+
+	backupInfo = wstate->backupInfo;
+	worker_conn = backupInfo->workerConns[wstate->workerid];
+	while ((fetchFile = getNextFile(backupInfo)) != NULL)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+		TablespaceInfo *curTsInfo = &backupInfo->tsInfo[fetchFile->tsIndex];
+
+
+		/*
+		 * build query in form of: SEND_BACKUP_FILES ('base/1/1245/32683',
+		 * 'base/1/1245/32683', ...) [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_BACKUP_FILES ( '%s' )", fetchFile->name);
+
+		/* add options */
+		appendPQExpBuffer(buf, " TABLESPACE_PATH '%s' START_WAL_LOCATION '%s' %s %s",
+						  curTsInfo->tablespace,
+						  backupInfo->xlogstart,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+
+		destroyPQExpBuffer(buf);
+
+		/* process file contents, also count bytesRead for progress */
+		wstate->bytesRead +=
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, fetchFile->tsIndex);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	return 0;
+}
+
+/*
+ * Increment fileIndex and store it in a local variable so that even a
+ * context switch does not affect the file index value and we don't accidentally
+ * increment the value twice and therefore skip some files.
+ */
+static BackupFile*
+getNextFile(BackupInfo *backupInfo)
+{
+	int fileIndex = 0;
+
+	pthread_mutex_lock(&fetch_mutex);
+	fileIndex = backupInfo->fileIndex++;
+	pthread_mutex_unlock(&fetch_mutex);
+
+	if (fileIndex >= backupInfo->totalfiles)
+		return NULL;
+
+	return backupInfo->files[fileIndex];
+}
+
+/* qsort comparator for BackupFile (sort descending order)  */
+static int
+compareFileSize(const void *a, const void *b)
+{
+	const		BackupFile *v1 = (BackupFile *) a;
+	const		BackupFile *v2 = (BackupFile *) b;
+
+	if (v1->size > v2->size)
+		return -1;
+	if (v1->size < v2->size)
+		return 1;
+
+	return 0;
+}
+
+static void
+read_label_tblspcmap(PGconn *conn, char **backuplabel, char **tblspc_map)
+{
+	PGresult   *res = NULL;
+
+	Assert(backuplabel != NULL);
+	Assert(tblspc_map != NULL);
+
+	/*
+	 * Get Backup label and tablespace map data.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) < 1)
+	{
+		pg_log_error("no data returned from server");
+		exit(1);
+	}
+
+	*backuplabel = PQgetvalue(res, 0, 0);	/* backup_label */
+	if (!PQgetisnull(res, 0, 1))
+		*tblspc_map = PQgetvalue(res, 0, 1);	/* tablespace_map */
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	PQclear(res);
+}
+
+/*
+ * Create backup direcotries while taking care of tablespace path. If tablespace
+ * mapping (with -T) is given then the directory will be created on the mapped
+ * path.
+ */
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char	dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+/*
+ * General function for writing to a file; creates one if it doesn't exist
+ */
+static void
+writefile(char *path, char *buf)
+{
+	FILE   *f;
+	char	pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
-- 
2.21.0 (Apple Git-122)

0001-Refactor-some-basebackup-code-to-increase-reusabilit_v3.patchapplication/octet-stream; name=0001-Refactor-some-basebackup-code-to-increase-reusabilit_v3.patchDownload
From 3c0dc234ab7d4fd88261a0cf16727a7ebbf1e69e Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 9 Oct 2019 12:39:41 +0500
Subject: [PATCH 1/5] Refactor some basebackup code to increase reusability, in
 anticipation of adding parallel backup

---
 src/backend/access/transam/xlog.c    | 192 +++++-----
 src/backend/replication/basebackup.c | 512 ++++++++++++++-------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 371 insertions(+), 335 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 2e3cc51006..aa7d82a045 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10286,10 +10286,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10415,93 +10411,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collectTablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12277,3 +12187,103 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+				   bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to
+		 * ensure that we can distinguish between the newline in the
+		 * tablespace path and end of line while reading tablespace_map
+		 * file during archive recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory
+		 * when it's located within PGDATA, or NULL if it's located
+		 * elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created
+		 * them. Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index d0f210de8c..5f25f5848d 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -68,10 +68,12 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt);
+static void include_wal_files(XLogRecPtr endptr);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
+static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
@@ -293,29 +295,7 @@ perform_base_backup(basebackup_options *opt)
 		/* Send tablespace header */
 		SendBackupHeader(tablespaces);
 
-		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
-
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		setup_throttle(opt->maxrate);
 
 		/* Send off our tablespaces one by one */
 		foreach(lc, tablespaces)
@@ -384,227 +364,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -1743,3 +1503,267 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * Append the required WAL files to the backup tar file. It assumes that the
+ * last tar file is "open" and the WALs will be appended to it.
+ */
+static void
+include_wal_files(XLogRecPtr endptr)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the
+	 * required WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and
+	 * include all WAL files in the range between 'startptr' and 'endptr',
+	 * regardless of the timeline the file is stamped with. If there are
+	 * some spurious WAL files belonging to timelines that don't belong in
+	 * this server's history, they will be included too. Normally there
+	 * shouldn't be such files, but if there are, there's little harm in
+	 * including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we
+	 * need were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from
+	 * oldest to newest, to reduce the chance that a file is recycled
+	 * before we get a chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since
+	 * we are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		CHECK_FREAD_ERROR(fp, pathbuf);
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again
+		 * after promotion of a new node. This is in line with
+		 * walreceiver.c always doing an XLogArchiveForceDone() after a
+		 * complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history
+	 * file is required for recovery, and even that only if there happens
+	 * to be a timeline switch in the first WAL segment that contains the
+	 * checkpoint record, or if we're taking a base backup from a standby
+	 * server and the target timeline changes while the backup is taken.
+	 * But they are small and highly useful for debugging purposes, so
+	 * better include them all, always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d519252aad..5b0aa8ae85 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 									 bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
+extern void collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+							   bool infotbssize, bool needtblspcmapfile);
 extern void do_pg_abort_backup(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.0 (Apple Git-122)

0002-backend-changes-for-parallel-backup_v3.patchapplication/octet-stream; name=0002-backend-changes-for-parallel-backup_v3.patchDownload
From ffb578517e75d81f175cdbb86a6d3f62e971ccda Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 22:59:28 +0500
Subject: [PATCH 2/5] backend changes for parallel backup

---
 src/backend/access/transam/xlog.c      |   2 +-
 src/backend/replication/basebackup.c   | 522 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    |  72 ++++
 src/backend/replication/repl_scanner.l |   7 +
 src/include/nodes/replnodes.h          |  10 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 604 insertions(+), 11 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index aa7d82a045..842b317c8d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -12265,7 +12265,7 @@ collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 5f25f5848d..4a382c4558 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -41,6 +41,7 @@
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
+#include "utils/pg_lsn.h"
 
 
 typedef struct
@@ -52,11 +53,34 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	const char *tablespace_path;
+	XLogRecPtr	wal_location;
 } basebackup_options;
 
+typedef struct
+{
+	char		name[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
+#define STORE_BACKUPFILE(_backupfiles, _name, _type, _size, _mtime) \
+	do { \
+		if (_backupfiles != NULL) { \
+			BackupFile *file = palloc0(sizeof(BackupFile)); \
+			strlcpy(file->name, _name, sizeof(file->name)); \
+			file->type = _type; \
+			file->size = _size; \
+			file->mtime = _mtime; \
+			*_backupfiles = lappend(*_backupfiles, file); \
+		} \
+	} while(0)
 
 static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
 					 List *tablespaces, bool sendtblspclinks);
+static int64 sendDir_(const char *path, int basepathlen, bool sizeonly,
+					  List *tablespaces, bool sendtblspclinks, List **files);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -76,6 +100,11 @@ static void throttle(size_t increment);
 static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendBackupManifest(basebackup_options *opt);
+static void SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -337,7 +366,7 @@ perform_base_backup(basebackup_options *opt)
 				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 			}
 			else
-				sendTablespace(ti->path, false);
+				sendTablespace(ti->path, false, NULL);
 
 			/*
 			 * If we're including WAL, and this is the main data directory we
@@ -412,6 +441,8 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_tablespace_path = false;
+	bool		o_wal_location = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -500,6 +531,29 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "tablespace_path") == 0)
+		{
+			if (o_tablespace_path)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+			opt->tablespace_path = strVal(defel->arg);
+			o_tablespace_path = true;
+		}
+		else if (strcmp(defel->defname, "start_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *wal_location;
+
+			if (o_wal_location)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			wal_location = strVal(defel->arg);
+			opt->wal_location = pg_lsn_in_internal(wal_location, &have_error);
+			o_wal_location = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -534,7 +588,29 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_BACKUP_MANIFEST:
+			SendBackupManifest(&opt);
+			break;
+		case SEND_BACKUP_FILES:
+			SendBackupFiles(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -677,6 +753,61 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_puttextmessage('C', "SELECT");
 }
 
+/*
+ * Send a single resultset containing backup label and tablespace map
+ */
+static void
+SendStartBackupResult(StringInfo labelfile, StringInfo tblspc_map_file)
+{
+	StringInfoData buf;
+	Size		len;
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);		/* 2 fields */
+
+	/* Field headers */
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "tablespacemap");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint16(&buf, 2);		/* number of columns */
+
+	len = labelfile->len;
+	pq_sendint32(&buf, len);
+	pq_sendbytes(&buf, labelfile->data, len);
+
+	if (tblspc_map_file)
+	{
+		len = tblspc_map_file->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, tblspc_map_file->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
+	}
+
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -728,7 +859,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool sizeonly, List **files)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -757,11 +888,11 @@ sendTablespace(char *path, bool sizeonly)
 		return 0;
 	}
 
+	STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   sizeonly);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir_(pathbuf, strlen(path), sizeonly, NIL, true, files);
 
 	return size;
 }
@@ -779,8 +910,16 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
-		bool sendtblspclinks)
+sendDir(const char *path, int basepathlen, bool sizeonly,
+		List *tablespaces, bool sendtblspclinks)
+{
+	return sendDir_(path, basepathlen, sizeonly, tablespaces, sendtblspclinks, NULL);
+}
+
+/* Same as sendDir(), except that it also returns a list of filenames in PGDATA */
+static int64
+sendDir_(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+		 bool sendtblspclinks, List **files)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -934,6 +1073,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 				excludeFound = true;
 				break;
@@ -950,6 +1091,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
 			continue;
 		}
@@ -971,6 +1114,9 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									sizeonly);
 
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
+			STORE_BACKUPFILE(files, "./pg_wal/archive_status", 'd', -1, statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -1000,6 +1146,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			STORE_BACKUPFILE(files, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, sizeonly);
 #else
@@ -1026,6 +1173,8 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									sizeonly);
+			STORE_BACKUPFILE(files, pathbuf, 'd', -1, statbuf.st_mtime);
+
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1056,13 +1205,15 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir_(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks, files);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			STORE_BACKUPFILE(files, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!sizeonly && files == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1767,3 +1918,356 @@ setup_throttle(int maxrate)
 		throttling_counter = -1;
 	}
 }
+
+/*
+ * StartBackup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, *all* functionality between do_pg_start_backup() and the end of
+	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 */
+
+	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	{
+		tablespaceinfo *ti;
+
+		SendXlogRecPtrResult(startptr, starttli);
+
+		/*
+		 * Calculate the relative path of temporary statistics directory in
+		 * order to skip the files which are located in that directory later.
+		 */
+		if (is_absolute_path(pgstat_stat_directory) &&
+			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+			statrelpath = psprintf("./%s", pgstat_stat_directory);
+		else
+			statrelpath = pgstat_stat_directory;
+
+		/* Add a node for the base directory at the end */
+		ti = palloc0(sizeof(tablespaceinfo));
+		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+		tablespaces = lappend(tablespaces, ti);
+
+		/* Send tablespace header */
+		SendBackupHeader(tablespaces);
+
+		/* Setup and activate network throttling, if client requested it */
+		setup_throttle(opt->maxrate);
+
+		if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
+			!opt->sendtblspcmapfile)
+			tblspc_map_file = NULL;
+
+		/* send backup_label and tablespace_map to frontend */
+		SendStartBackupResult(labelfile, tblspc_map_file);
+	}
+	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+}
+
+/*
+ * StopBackup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionaly WAL segments and ending WAL location.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile = NULL;
+
+	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+	{
+		/* Setup and activate network throttling, if client requested it */
+		setup_throttle(opt->maxrate);
+
+		pq_beginmessage(&buf, 'H');
+		pq_sendbyte(&buf, 0);		/* overall format */
+		pq_sendint16(&buf, 0);		/* natts */
+		pq_endmessage(&buf);
+
+		/* ... and pg_control after everything else. */
+		if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							XLOG_CONTROL_FILE)));
+		sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+		/* stop backup */
+		endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+		if (opt->includewal)
+			include_wal_files(endptr);
+
+		pq_putemptymessage('c');	/* CopyDone */
+		SendXlogRecPtrResult(endptr, endtli);
+	}
+	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
+}
+
+/*
+ * SendBackupManifest() - sends a list of filenames to frontend
+ *
+ * The function collects a list of filenames, necessary for a complete backup and
+ * sends this list to the client.
+ */
+static void
+SendBackupManifest(basebackup_options *opt)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	List	   *tablespaces = NIL;
+	StringInfo	tblspc_map_file = NULL;
+
+	tblspc_map_file = makeStringInfo();
+	collectTablespaces(&tablespaces, tblspc_map_file, false, false);
+
+	/* Add a node for the base directory at the end */
+	tablespaceinfo *ti = palloc0(sizeof(tablespaceinfo));
+	tablespaces = lappend(tablespaces, ti);
+
+	foreach(lc, tablespaces)
+	{
+		List	   *backupFiles = NULL;
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+
+		if (ti->path == NULL)
+			sendDir_(".", 1, false, NIL, !opt->sendtblspcmapfile, &backupFiles);
+		else
+			sendTablespace(ti->path, false, &backupFiles);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 4);	/* n field */
+
+		/* First field - file name */
+		pq_sendstring(&buf, "filename");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "type");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, CHAROID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - mtime */
+		pq_sendstring(&buf, "mtime");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, backupFiles)
+		{
+			BackupFile *backupFile = (BackupFile *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 4);	/* number of columns */
+
+			/* send file name */
+			len = strlen(backupFile->name);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, backupFile->name, len);
+
+			/* send type */
+			pq_sendint32(&buf, 1);
+			pq_sendbyte(&buf, backupFile->type);
+
+			/* send size */
+			send_int8_string(&buf, backupFile->size);
+
+			/* send mtime */
+			send_int8_string(&buf, backupFile->mtime);
+
+			pq_endmessage(&buf);
+		}
+
+		pfree(backupFiles);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendBackupFiles() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol.
+ */
+static void
+SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	bool		basetablespace = true;
+	int			basepathlen = 1;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	if (is_absolute_path(opt->tablespace_path))
+	{
+		basepathlen = strlen(opt->tablespace_path);
+		basetablespace = false;
+	}
+
+	/* set backup start location. */
+	startptr = opt->wal_location;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/* Allow symbolic links in pg_tblspc only */
+		if (strstr(pathbuf, "./pg_tblspc") != NULL &&
+#ifndef WIN32
+			S_ISLNK(statbuf.st_mode)
+#else
+			pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			char		linkpath[MAXPGPATH];
+			int			rllen;
+
+			rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not read symbolic link \"%s\": %m",
+								pathbuf)));
+			if (rllen >= sizeof(linkpath))
+				ereport(ERROR,
+						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+						 errmsg("symbolic link \"%s\" target is too long",
+								pathbuf)));
+			linkpath[rllen] = '\0';
+
+			_tarWriteHeader(pathbuf, linkpath, &statbuf, false);
+		}
+		else if (S_ISDIR(statbuf.st_mode))
+		{
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else if (
+#ifndef WIN32
+				 S_ISLNK(statbuf.st_mode)
+#else
+				 pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			/*
+			 * If symlink, write it as a directory. file symlinks only allowed
+			 * in pg_tblspc
+			 */
+			statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report total checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..9e2499814b 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,6 +87,12 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_BACKUP_MANIFEST
+%token K_SEND_BACKUP_FILES
+%token K_STOP_BACKUP
+%token K_START_WAL_LOCATION
+%token K_TABLESPACE_PATH
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
@@ -102,6 +108,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -162,6 +170,36 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_START_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_MANIFEST base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = SEND_BACKUP_MANIFEST;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_FILES backup_files base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_BACKUP_FILES;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
@@ -214,6 +252,40 @@ base_backup_opt:
 				  $$ = makeDefElem("noverify_checksums",
 								   (Node *)makeInteger(true), -1);
 				}
+			| K_START_WAL_LOCATION SCONST
+				{
+				  $$ = makeDefElem("start_wal_location",
+								   (Node *)makeString($2), -1);
+				}
+			| K_TABLESPACE_PATH SCONST
+				{
+				  $$ = makeDefElem("tablespace_path",
+								   (Node *)makeString($2), -1);
+				}
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{
+					$$ = $2;
+				}
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
+				{
+					$$ = list_make1($1);
+				}
+			| backup_files_list ',' backup_file
+				{
+					$$ = lappend($1, $3);
+				}
+			;
+
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..7a1bb54da8 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,13 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_BACKUP_MANIFEST	{ return K_SEND_BACKUP_MANIFEST; }
+SEND_BACKUP_FILES	{ return K_SEND_BACKUP_FILES; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
+TABLESPACE_PATH		{ return K_TABLESPACE_PATH; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..bc47446176 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,14 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_BACKUP_MANIFEST,
+	SEND_BACKUP_FILES,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +50,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..9e792af99d 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool sizeonly, List **files);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122)

#28Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#27)
Re: WIP/PoC for parallel backup

On Mon, Oct 28, 2019 at 10:03 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

I have updated the patch to include the changes suggested by Jeevan. This patch also implements the thread workers instead of
processes and fetches a single file at a time. The tar format has been disabled for first version of parallel backup.

Looking at 0001-0003:

It's not clear to me what the purpose of the start WAL location is
supposed to be. As far as I can see, SendBackupFiles() stores it in a
variable which is then used for exactly nothing, and nothing else uses
it. It seems like that would be part of a potential incremental
backup feature, but I don't see what it's got to do with parallel full
backup.

The tablespace_path option appears entirely unused, and I don't know
why that should be necessary here, either.

STORE_BACKUPFILE() seems like maybe it should be a function rather
than a macro, and also probably be renamed, because it doesn't store
files and the argument's not necessarily a file.

SendBackupManifest() does not send a backup manifest in the sense
contemplated by the email thread on that subject. It sends a file
list. That seems like the right idea - IMHO, anyway - but you need to
do a thorough renaming.

I think it would be fine to decide that this facility won't support
exclusive-mode backup.

I don't think much of having both sendDir() and sendDir_(). The latter
name is inconsistent with any naming convention we have, and there
seems to be no reason not to just add an argument to sendDir() and
change the callers.

I think we should rename - perhaps as a preparatory patch - the
sizeonly flag to dryrun, or something like that.

The resource cleanup does not look right. You've included calls to
PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, 0) in both StartBackup()
and StopBackup(), but what happens if there is an error or even a
clean shutdown of the connection in between? I think that there needs
to be some change here to ensure that a walsender will always call
base_backup_cleanup() when it exits; I think that'd probably remove
the need for any PG_ENSURE_ERROR_CLEANUP calls at all, including ones
we have already. This might also be something that could be done as a
separate, prepatory refactoring patch.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#29Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#28)
Re: WIP/PoC for parallel backup

On Mon, Oct 28, 2019 at 8:29 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Oct 28, 2019 at 10:03 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I have updated the patch to include the changes suggested by Jeevan.

This patch also implements the thread workers instead of

processes and fetches a single file at a time. The tar format has been

disabled for first version of parallel backup.

Looking at 0001-0003:

It's not clear to me what the purpose of the start WAL location is
supposed to be. As far as I can see, SendBackupFiles() stores it in a
variable which is then used for exactly nothing, and nothing else uses
it. It seems like that would be part of a potential incremental
backup feature, but I don't see what it's got to do with parallel full
backup.

'startptr' is used by sendFile() during checksum verification. Since
SendBackupFiles() is using sendFIle we have to set a valid WAL location.

The tablespace_path option appears entirely unused, and I don't know
why that should be necessary here, either.

This is to calculate the basepathlen. We need to exclude the tablespace
location (or
base path) from the filename before it is sent to the client with sendFile
call. I added
this option primarily to avoid performing string manipulation on filename
to extract the
tablespace location and then calculate the basepathlen.

Alternatively we can do it by extracting the base path from the received
filename. What
do you suggest?

STORE_BACKUPFILE() seems like maybe it should be a function rather
than a macro, and also probably be renamed, because it doesn't store
files and the argument's not necessarily a file.

Sure.

SendBackupManifest() does not send a backup manifest in the sense
contemplated by the email thread on that subject. It sends a file
list. That seems like the right idea - IMHO, anyway - but you need to
do a thorough renaming.

I'm considering the following command names:
START_BACKUP
- Starts the backup process

SEND_BACKUP_FILELIST (Instead of SEND_BACKUP_MANIFEST)
- Sends the list of all files (along with file information such as
filename, file type (directory/file/link),
file size and file mtime for each file) to be backed up.

SEND_BACKUP_FILES
- Sends one or more files to the client.

STOP_BACKUP
- Stops the backup process.

I'll update the function names accordingly after your confirmation. Of
course, suggestions for
better names are welcome.

I think it would be fine to decide that this facility won't support
exclusive-mode backup.

Sure. Will drop this patch.

I don't think much of having both sendDir() and sendDir_(). The latter
name is inconsistent with any naming convention we have, and there
seems to be no reason not to just add an argument to sendDir() and
change the callers.

I think we should rename - perhaps as a preparatory patch - the
sizeonly flag to dryrun, or something like that.

Sure, will take care of it.

The resource cleanup does not look right. You've included calls to
PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, 0) in both StartBackup()
and StopBackup(), but what happens if there is an error or even a
clean shutdown of the connection in between? I think that there needs

to be some change here to ensure that a walsender will always call

base_backup_cleanup() when it exits; I think that'd probably remove
the need for any PG_ENSURE_ERROR_CLEANUP calls at all, including ones
we have already. This might also be something that could be done as a
separate, prepatory refactoring patch.

You're right. I didn't handle this case properly. I will removed
PG_ENSURE_ERROR_CLEANUP
calls and replace it with before_shmem_exit handler. This way
whenever backend process exits,
base_backup_cleanup will be called:
- If it exists before calling the do_pg_stop_backup, base_backup_cleanup
will take care of cleanup.
- otherwise in case of a clean shutdown (after calling do_pg_stop_backup)
then base_backup_cleanup
will simply return without doing anything.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#30Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#29)
6 attachment(s)
Re: WIP/PoC for parallel backup

On Wed, Oct 30, 2019 at 7:16 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Mon, Oct 28, 2019 at 8:29 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Oct 28, 2019 at 10:03 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I have updated the patch to include the changes suggested by Jeevan.

This patch also implements the thread workers instead of

processes and fetches a single file at a time. The tar format has been

disabled for first version of parallel backup.

Looking at 0001-0003:

It's not clear to me what the purpose of the start WAL location is
supposed to be. As far as I can see, SendBackupFiles() stores it in a
variable which is then used for exactly nothing, and nothing else uses
it. It seems like that would be part of a potential incremental
backup feature, but I don't see what it's got to do with parallel full
backup.

'startptr' is used by sendFile() during checksum verification. Since
SendBackupFiles() is using sendFIle we have to set a valid WAL location.

The tablespace_path option appears entirely unused, and I don't know
why that should be necessary here, either.

This is to calculate the basepathlen. We need to exclude the tablespace
location (or
base path) from the filename before it is sent to the client with sendFile
call. I added
this option primarily to avoid performing string manipulation on filename
to extract the
tablespace location and then calculate the basepathlen.

Alternatively we can do it by extracting the base path from the received
filename. What
do you suggest?

STORE_BACKUPFILE() seems like maybe it should be a function rather
than a macro, and also probably be renamed, because it doesn't store
files and the argument's not necessarily a file.

Sure.

SendBackupManifest() does not send a backup manifest in the sense
contemplated by the email thread on that subject. It sends a file
list. That seems like the right idea - IMHO, anyway - but you need to
do a thorough renaming.

I'm considering the following command names:
START_BACKUP
- Starts the backup process

SEND_BACKUP_FILELIST (Instead of SEND_BACKUP_MANIFEST)
- Sends the list of all files (along with file information such as
filename, file type (directory/file/link),
file size and file mtime for each file) to be backed up.

SEND_BACKUP_FILES
- Sends one or more files to the client.

STOP_BACKUP
- Stops the backup process.

I'll update the function names accordingly after your confirmation. Of
course, suggestions for
better names are welcome.

I think it would be fine to decide that this facility won't support
exclusive-mode backup.

Sure. Will drop this patch.

I don't think much of having both sendDir() and sendDir_(). The latter
name is inconsistent with any naming convention we have, and there
seems to be no reason not to just add an argument to sendDir() and
change the callers.

I think we should rename - perhaps as a preparatory patch - the
sizeonly flag to dryrun, or something like that.

Sure, will take care of it.

The resource cleanup does not look right. You've included calls to
PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, 0) in both StartBackup()
and StopBackup(), but what happens if there is an error or even a
clean shutdown of the connection in between? I think that there needs

to be some change here to ensure that a walsender will always call

base_backup_cleanup() when it exits; I think that'd probably remove
the need for any PG_ENSURE_ERROR_CLEANUP calls at all, including ones
we have already. This might also be something that could be done as a
separate, prepatory refactoring patch.

You're right. I didn't handle this case properly. I will removed
PG_ENSURE_ERROR_CLEANUP
calls and replace it with before_shmem_exit handler. This way
whenever backend process exits,
base_backup_cleanup will be called:
- If it exists before calling the do_pg_stop_backup, base_backup_cleanup
will take care of cleanup.
- otherwise in case of a clean shutdown (after calling do_pg_stop_backup)
then base_backup_cleanup
will simply return without doing anything.

The updated patches are attached.

Thanks,

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v4.patchapplication/octet-stream; name=0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v4.patchDownload
From bc21821fde87bbcca31dfecf3fd482e38967a586 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 16:45:28 +0500
Subject: [PATCH 2/6] Rename sizeonly to dryrun for few functions in
 basebackup.

---
 src/backend/replication/basebackup.c | 44 ++++++++++++++--------------
 src/include/replication/basebackup.h |  2 +-
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index c640748c35..9442486b66 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -55,15 +55,15 @@ typedef struct
 } basebackup_options;
 
 
-static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
+static int64 sendDir(const char *path, int basepathlen, bool dryrun,
 					 List *tablespaces, bool sendtblspclinks);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
 static int64 _tarWriteHeader(const char *filename, const char *linktarget,
-							 struct stat *statbuf, bool sizeonly);
+							 struct stat *statbuf, bool dryrun);
 static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-						  bool sizeonly);
+						  bool dryrun);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
@@ -960,13 +960,13 @@ sendFileWithContent(const char *filename, const char *content)
 
 /*
  * Include the tablespace directory pointed to by 'path' in the output tar
- * stream.  If 'sizeonly' is true, we just calculate a total length and return
+ * stream.  If 'dryrun' is true, we just calculate a total length and return
  * it, without actually sending anything.
  *
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool dryrun)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -996,17 +996,17 @@ sendTablespace(char *path, bool sizeonly)
 	}
 
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
-						   sizeonly);
+						   dryrun);
 
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
 
 	return size;
 }
 
 /*
  * Include all files from the given directory in the output tar stream. If
- * 'sizeonly' is true, we just calculate a total length and return it, without
+ * 'dryrun' is true, we just calculate a total length and return it, without
  * actually sending anything.
  *
  * Omit any directory in the tablespaces list, to avoid backing up
@@ -1017,7 +1017,7 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		bool sendtblspclinks)
 {
 	DIR		   *dir;
@@ -1172,7 +1172,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
-				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
 			}
@@ -1188,7 +1188,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
 
@@ -1200,14 +1200,14 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (strcmp(pathbuf, "./pg_wal") == 0)
 		{
 			/* If pg_wal is a symlink, write it as a directory anyway */
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 
 			/*
 			 * Also send archive_status directory (by hackishly reusing
 			 * statbuf from above ...).
 			 */
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			continue;			/* don't recurse into pg_wal */
 		}
@@ -1239,7 +1239,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			linkpath[rllen] = '\0';
 
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
-									&statbuf, sizeonly);
+									&statbuf, dryrun);
 #else
 
 			/*
@@ -1263,7 +1263,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 * permissions right.
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1294,17 +1294,17 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			if (!dryrun)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
-			if (sent || sizeonly)
+			if (sent || dryrun)
 			{
 				/* Add size, rounded up to 512byte block */
 				size += ((statbuf.st_size + 511) & ~511);
@@ -1613,12 +1613,12 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
 
 static int64
 _tarWriteHeader(const char *filename, const char *linktarget,
-				struct stat *statbuf, bool sizeonly)
+				struct stat *statbuf, bool dryrun)
 {
 	char		h[512];
 	enum tarError rc;
 
-	if (!sizeonly)
+	if (!dryrun)
 	{
 		rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
 							 statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
@@ -1655,7 +1655,7 @@ _tarWriteHeader(const char *filename, const char *linktarget,
  */
 static int64
 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-			 bool sizeonly)
+			 bool dryrun)
 {
 	/* If symlink, write it as a directory anyway */
 #ifndef WIN32
@@ -1665,7 +1665,7 @@ _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
 #endif
 		statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
 
-	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
+	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, dryrun);
 }
 
 /*
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..b55917b9b6 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool dryrun);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122)

0001-remove-PG_ENSURE_ERROR_CLEANUP-macro-from-basebackup_v4.patchapplication/octet-stream; name=0001-remove-PG_ENSURE_ERROR_CLEANUP-macro-from-basebackup_v4.patchDownload
From 3f37a9014ecc43679a1bffc1d3f54d2a266512c1 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 10:21:38 +0500
Subject: [PATCH 1/6] remove PG_ENSURE_ERROR_CLEANUP macro from basebackup.
 register base_backup_cleanup with before_shmem_exit handler. This will make
 sure that call is always made when wal sender exits.

---
 src/backend/replication/basebackup.c | 182 +++++++++++++--------------
 1 file changed, 90 insertions(+), 92 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index d0f210de8c..c640748c35 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -244,6 +244,8 @@ perform_base_backup(basebackup_options *opt)
 	StringInfo	tblspc_map_file = NULL;
 	int			datadirpathlen;
 	List	   *tablespaces = NIL;
+	ListCell   *lc;
+	tablespaceinfo *ti;
 
 	datadirpathlen = strlen(DataDir);
 
@@ -262,121 +264,117 @@ perform_base_backup(basebackup_options *opt)
 	/*
 	 * Once do_pg_start_backup has been called, ensure that any failure causes
 	 * us to abort the backup so we don't "leak" a backup counter. For this
-	 * reason, *all* functionality between do_pg_start_backup() and the end of
-	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 * reason, register base_backup_cleanup with before_shmem_exit handler. This
+	 * will make sure that call is always made when process exits. In success,
+	 * do_pg_stop_backup will have taken the system out of backup mode and this
+	 * callback will have no effect, Otherwise the required cleanup will be done
+	 * in any case.
 	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
 
-	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
-	{
-		ListCell   *lc;
-		tablespaceinfo *ti;
-
-		SendXlogRecPtrResult(startptr, starttli);
+	SendXlogRecPtrResult(startptr, starttli);
 
-		/*
-		 * Calculate the relative path of temporary statistics directory in
-		 * order to skip the files which are located in that directory later.
-		 */
-		if (is_absolute_path(pgstat_stat_directory) &&
-			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
-		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory);
-		else
-			statrelpath = pgstat_stat_directory;
-
-		/* Add a node for the base directory at the end */
-		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
-		tablespaces = lappend(tablespaces, ti);
+	/*
+	 * Calculate the relative path of temporary statistics directory in
+	 * order to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
 
-		/* Send tablespace header */
-		SendBackupHeader(tablespaces);
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	tablespaces = lappend(tablespaces, ti);
 
-		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
 
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
+	/* Setup and activate network throttling, if client requested it */
+	if (opt->maxrate > 0)
+	{
+		throttling_sample =
+			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
 
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
 
-		/* Send off our tablespaces one by one */
-		foreach(lc, tablespaces)
-		{
-			tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
-			StringInfoData buf;
+		/* Enable throttling. */
+		throttling_counter = 0;
 
-			/* Send CopyOutResponse message */
-			pq_beginmessage(&buf, 'H');
-			pq_sendbyte(&buf, 0);	/* overall format */
-			pq_sendint16(&buf, 0);	/* natts */
-			pq_endmessage(&buf);
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
 
-			if (ti->path == NULL)
-			{
-				struct stat statbuf;
+	/* Send off our tablespaces one by one */
+	foreach(lc, tablespaces)
+	{
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+		StringInfoData buf;
 
-				/* In the main tar, include the backup_label first... */
-				sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
+		/* Send CopyOutResponse message */
+		pq_beginmessage(&buf, 'H');
+		pq_sendbyte(&buf, 0);	/* overall format */
+		pq_sendint16(&buf, 0);	/* natts */
+		pq_endmessage(&buf);
 
-				/*
-				 * Send tablespace_map file if required and then the bulk of
-				 * the files.
-				 */
-				if (tblspc_map_file && opt->sendtblspcmapfile)
-				{
-					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-					sendDir(".", 1, false, tablespaces, false);
-				}
-				else
-					sendDir(".", 1, false, tablespaces, true);
+		if (ti->path == NULL)
+		{
+			struct stat statbuf;
 
-				/* ... and pg_control after everything else. */
-				if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
-					ereport(ERROR,
-							(errcode_for_file_access(),
-							 errmsg("could not stat file \"%s\": %m",
-									XLOG_CONTROL_FILE)));
-				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
-			}
-			else
-				sendTablespace(ti->path, false);
+			/* In the main tar, include the backup_label first... */
+			sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
 
 			/*
-			 * If we're including WAL, and this is the main data directory we
-			 * don't terminate the tar stream here. Instead, we will append
-			 * the xlog files below and terminate it then. This is safe since
-			 * the main data directory is always sent *last*.
+			 * Send tablespace_map file if required and then the bulk of
+			 * the files.
 			 */
-			if (opt->includewal && ti->path == NULL)
+			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
-				Assert(lnext(tablespaces, lc) == NULL);
+				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
+				sendDir(".", 1, false, tablespaces, false);
 			}
 			else
-				pq_putemptymessage('c');	/* CopyDone */
+				sendDir(".", 1, false, tablespaces, true);
+
+			/* ... and pg_control after everything else. */
+			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file \"%s\": %m",
+								XLOG_CONTROL_FILE)));
+			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
+		else
+			sendTablespace(ti->path, false);
 
-		endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+		/*
+		 * If we're including WAL, and this is the main data directory we
+		 * don't terminate the tar stream here. Instead, we will append
+		 * the xlog files below and terminate it then. This is safe since
+		 * the main data directory is always sent *last*.
+		 */
+		if (opt->includewal && ti->path == NULL)
+		{
+			Assert(lnext(tablespaces, lc) == NULL);
+		}
+		else
+			pq_putemptymessage('c');	/* CopyDone */
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 
+	endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
 
 	if (opt->includewal)
 	{
-- 
2.21.0 (Apple Git-122)

0005-pg_basebackup-changes-for-parallel-backup_v4.patchapplication/octet-stream; name=0005-pg_basebackup-changes-for-parallel-backup_v4.patchDownload
From 16b77550d4e4e185b6bb45176301212db0edb09b Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 14 Oct 2019 17:28:58 +0500
Subject: [PATCH 5/6] pg_basebackup changes for parallel backup.

---
 src/bin/pg_basebackup/pg_basebackup.c | 710 ++++++++++++++++++++++++--
 1 file changed, 672 insertions(+), 38 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index a9d162a7da..9dd7c62933 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -19,6 +19,7 @@
 #include <sys/wait.h>
 #include <signal.h>
 #include <time.h>
+#include <pthread.h>
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -41,6 +42,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -57,6 +59,57 @@ typedef struct TablespaceList
 	TablespaceListCell *tail;
 } TablespaceList;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+
+	int			tsIndex;	/* index of tsInfo this file belongs to. */
+} BackupFile;
+
+typedef struct
+{
+	Oid			tblspcOid;
+	char	   *tablespace;	 /* tablespace name or NULL if 'base' tablespace */
+	int			numFiles;	 /* number of files */
+	BackupFile *backupFiles; /* list of files in a tablespace */
+} TablespaceInfo;
+
+typedef struct
+{
+	int 	tablespacecount;
+	int		totalfiles;
+	int		numWorkers;
+
+	char	xlogstart[64];
+	char   *backup_label;
+	char   *tablespace_map;
+
+	TablespaceInfo *tsInfo;
+	BackupFile	  **files;		/* list of BackupFile pointers */
+	int				fileIndex;	/* index of file to be fetched */
+
+	PGconn	**workerConns;
+} BackupInfo;
+
+typedef struct
+{
+	BackupInfo *backupInfo;
+	uint64		bytesRead;
+
+	int			workerid;
+	pthread_t	worker;
+
+	bool	terminated;
+} WorkerState;
+
+BackupInfo *backupInfo = NULL;
+WorkerState *workers = NULL;
+
+static pthread_mutex_t fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -110,6 +163,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -140,9 +196,10 @@ static PQExpBuffer recoveryconfcontents = NULL;
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
+static void workers_progress_report(uint64 totalBytesRead, const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
-static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
+static int	ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
 
 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -151,6 +208,17 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupRun(BackupInfo *backupInfo);
+static void StopBackup(BackupInfo *backupInfo);
+static void GetBackupFileList(PGconn *conn, BackupInfo *backupInfo);
+static int GetBackupFile(WorkerState *wstate);
+static BackupFile *getNextFile(BackupInfo *backupInfo);
+static int	compareFileSize(const void *a, const void *b);
+static void read_label_tblspcmap(PGconn *conn, char **backup_label, char **tablespace_map);
+static void create_backup_dirs(bool basetablespace, char *tablespace, char *name);
+static void writefile(char *path, char *buf);
+static void *workerRun(void *arg);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -202,6 +270,17 @@ cleanup_directories_atexit(void)
 static void
 disconnect_atexit(void)
 {
+	/* close worker connections */
+	if (backupInfo && backupInfo->workerConns != NULL)
+	{
+		int i;
+		for (i = 0; i < numWorkers; i++)
+		{
+			if (backupInfo->workerConns[i] != NULL)
+				PQfinish(backupInfo->workerConns[i]);
+		}
+	}
+
 	if (conn != NULL)
 		PQfinish(conn);
 }
@@ -349,6 +428,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -695,6 +775,93 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 	}
 }
 
+/*
+ * Print a progress report of worker threads. If verbose output
+ * is enabled, also print the current file name.
+ *
+ * Progress report is written at maximum once per second, unless the
+ * force parameter is set to true.
+ */
+static void
+workers_progress_report(uint64 totalBytesRead, const char *filename, bool force)
+{
+	int			percent;
+	char		totalBytesRead_str[32];
+	char		totalsize_str[32];
+	pg_time_t	now;
+
+	if (!showprogress)
+		return;
+
+	now = time(NULL);
+	if (now == last_progress_report && !force)
+		return;					/* Max once per second */
+
+	last_progress_report = now;
+	percent = totalsize_kb ? (int) ((totalBytesRead / 1024) * 100 / totalsize_kb) : 0;
+
+	/*
+	 * Avoid overflowing past 100% or the full size. This may make the total
+	 * size number change as we approach the end of the backup (the estimate
+	 * will always be wrong if WAL is included), but that's better than having
+	 * the done column be bigger than the total.
+	 */
+	if (percent > 100)
+		percent = 100;
+	if (totalBytesRead / 1024 > totalsize_kb)
+		totalsize_kb = totalBytesRead / 1024;
+
+	/*
+	 * Separate step to keep platform-dependent format code out of
+	 * translatable strings.  And we only test for INT64_FORMAT availability
+	 * in snprintf, not fprintf.
+	 */
+	snprintf(totalBytesRead_str, sizeof(totalBytesRead_str), INT64_FORMAT,
+			 totalBytesRead / 1024);
+	snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
+
+#define VERBOSE_FILENAME_LENGTH 35
+
+	if (verbose)
+	{
+		if (!filename)
+
+			/*
+			 * No filename given, so clear the status line (used for last
+			 * call)
+			 */
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied %*s"),
+					(int) strlen(totalsize_str),
+					totalBytesRead_str, totalsize_str,
+					percent,
+					VERBOSE_FILENAME_LENGTH + 5, "");
+		else
+		{
+			bool		truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied, current file (%s%-*.*s)"),
+					(int) strlen(totalsize_str), totalBytesRead_str, totalsize_str,
+					percent,
+					/* Prefix with "..." if we do leading truncation */
+							truncate ? "..." : "",
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+					/* Truncate filename at beginning if it's too long */
+							truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+				(int) strlen(totalsize_str),
+				totalBytesRead_str, totalsize_str,
+				percent);
+	}
+
+	if (isatty(fileno(stderr)))
+		fprintf(stderr, "\r");
+	else
+		fprintf(stderr, "\n");
+}
 
 /*
  * Print a progress report based on the global variables. If verbose output
@@ -711,7 +878,7 @@ progress_report(int tablespacenum, const char *filename, bool force)
 	char		totalsize_str[32];
 	pg_time_t	now;
 
-	if (!showprogress)
+	if (!showprogress || numWorkers > 1)
 		return;
 
 	now = time(NULL);
@@ -1381,7 +1548,7 @@ get_tablespace_mapping(const char *dir)
  * specified directory. If it's for another tablespace, it will be restored
  * in the original or mapped directory.
  */
-static void
+static int
 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 {
 	char		current_path[MAXPGPATH];
@@ -1392,6 +1559,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	bool		basetablespace;
 	char	   *copybuf = NULL;
 	FILE	   *file = NULL;
+	int			readBytes = 0;
 
 	basetablespace = PQgetisnull(res, rownum, 0);
 	if (basetablespace)
@@ -1455,7 +1623,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("invalid tar block header size: %d", r);
 				exit(1);
 			}
-			totaldone += 512;
+			readBytes += 512;
 
 			current_len_left = read_tar_number(&copybuf[124], 12);
 
@@ -1486,21 +1654,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * Directory
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
+
+					/*
+					 * In parallel mode, we create directories before fetching
+					 * files so its Ok if a directory already exist.
+					 */
 					if (mkdir(filename, pg_dir_create_mode) != 0)
 					{
-						/*
-						 * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
-						 * clusters) will have been created by the wal
-						 * receiver process. Also, when the WAL directory
-						 * location was specified, pg_wal (or pg_xlog) has
-						 * already been created as a symbolic link before
-						 * starting the actual backup. So just ignore creation
-						 * failures on related directories.
-						 */
-						if (!((pg_str_endswith(filename, "/pg_wal") ||
-							   pg_str_endswith(filename, "/pg_xlog") ||
-							   pg_str_endswith(filename, "/archive_status")) &&
-							  errno == EEXIST))
+						if (errno != EEXIST)
 						{
 							pg_log_error("could not create directory \"%s\": %m",
 										 filename);
@@ -1585,7 +1746,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				 */
 				fclose(file);
 				file = NULL;
-				totaldone += r;
+				readBytes += r;
 				continue;
 			}
 
@@ -1594,7 +1755,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("could not write to file \"%s\": %m", filename);
 				exit(1);
 			}
-			totaldone += r;
+			readBytes += r;
+			totaldone = readBytes;
 			progress_report(rownum, filename, false);
 
 			current_len_left -= r;
@@ -1622,13 +1784,11 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	if (copybuf != NULL)
 		PQfreemem(copybuf);
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
-
 	/*
 	 * No data is synced here, everything is done for all tablespaces at the
 	 * end.
 	 */
+	return readBytes;
 }
 
 
@@ -1716,7 +1876,8 @@ BaseBackup(void)
 	}
 
 	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+		psprintf("%s LABEL '%s' %s %s %s %s %s %s %s",
+				 (numWorkers > 1) ? "START_BACKUP" : "BASE_BACKUP",
 				 escaped_label,
 				 showprogress ? "PROGRESS" : "",
 				 includewal == FETCH_WAL ? "WAL" : "",
@@ -1774,7 +1935,7 @@ BaseBackup(void)
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1830,24 +1991,74 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		int j = 0,
+			k = 0;
 
-	if (showprogress)
+		backupInfo = palloc0(sizeof(BackupInfo));
+		backupInfo->workerConns = (PGconn **) palloc0(sizeof(PGconn *) * numWorkers);
+		backupInfo->tablespacecount = tablespacecount;
+		backupInfo->numWorkers = numWorkers;
+		strlcpy(backupInfo->xlogstart, xlogstart, sizeof(backupInfo->xlogstart));
+
+		read_label_tblspcmap(conn, &backupInfo->backup_label, &backupInfo->tablespace_map);
+
+		/* retrieve backup file list from the server. **/
+		GetBackupFileList(conn, backupInfo);
+
+		/*
+		 * add backup_label in backup, (for tar format, ReceiveTarFile() will
+		 * take care of it).
+		 */
+		if (format == 'p')
+			writefile("backup_label", backupInfo->backup_label);
+
+		/*
+		 * Flatten the file list to avoid unnecessary locks and enable the sequential
+		 * access to file list. (Creating an array of BackupFile structre pointers).
+		 */
+		backupInfo->files =
+			(BackupFile **) palloc0(sizeof(BackupFile *) * backupInfo->totalfiles);
+		for (i = 0; i < backupInfo->tablespacecount; i++)
+		{
+			TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+
+			for (j = 0; j < curTsInfo->numFiles; j++)
+			{
+				backupInfo->files[k] = &curTsInfo->backupFiles[j];
+				k++;
+			}
+		}
+
+		ParallelBackupRun(backupInfo);
+		StopBackup(backupInfo);
+	}
+	else
 	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+
+		if (showprogress)
+		{
+			progress_report(PQntuples(tablespacehdr), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
 	}
 
+	/* Write recovery contents */
+	if (format == 'p' && writerecoveryconf)
+		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
+
 	PQclear(res);
 
 	/*
@@ -2043,6 +2254,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2070,7 +2282,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2211,6 +2423,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2325,6 +2540,22 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (format != 'p' && numWorkers > 1)
+	{
+		pg_log_error("parallel jobs are only supported with 'plain' format");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2397,3 +2628,406 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+/*
+ * Thread worker
+ */
+static void *
+workerRun(void *arg)
+{
+	WorkerState *wstate = (WorkerState *) arg;
+
+	GetBackupFile(wstate);
+
+	wstate->terminated = true;
+	return NULL;
+}
+
+/*
+ * Runs the worker threads and updates progress until all workers have
+ * terminated/completed.
+ */
+static void
+ParallelBackupRun(BackupInfo *backupInfo)
+{
+	int		status,
+			i;
+	bool	threadsActive = true;
+	uint64	totalBytes = 0;
+
+	workers = (WorkerState *) palloc0(sizeof(WorkerState) * numWorkers);
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		WorkerState *worker = &workers[i];
+
+		worker->backupInfo = backupInfo;
+		worker->workerid = i;
+		worker->bytesRead = 0;
+		worker->terminated = false;
+
+		backupInfo->workerConns[i] = GetConnection();
+		status = pthread_create(&worker->worker, NULL, workerRun, worker);
+		if (status != 0)
+		{
+			pg_log_error("failed to create thread: %m");
+			exit(1);
+		}
+
+		if (verbose)
+			pg_log_info("backup worker (%d) created, %d", i, status);
+	}
+
+	/*
+	 * This is the main thread for updating progrsss. It waits for workers to
+	 * complete and gets updated status during every loop iteration.
+	 */
+	while(threadsActive)
+	{
+		char *filename = NULL;
+
+		threadsActive = false;
+		totalBytes = 0;
+
+		for (i = 0; i < numWorkers; i++)
+		{
+			WorkerState *worker = &workers[i];
+
+			totalBytes += worker->bytesRead;
+			threadsActive |= !worker->terminated;
+		}
+
+		if (backupInfo->fileIndex < backupInfo->totalfiles)
+			filename = backupInfo->files[backupInfo->fileIndex]->path;
+
+		workers_progress_report(totalBytes, filename, false);
+		pg_usleep(100000);
+	}
+
+	if (showprogress)
+	{
+		workers_progress_report(totalBytes, NULL, true);
+		if (isatty(fileno(stderr)))
+			fprintf(stderr, "\n");	/* Need to move to next line */
+	}
+}
+
+/*
+ * Take the system out of backup mode.
+ */
+static void
+StopBackup(BackupInfo *backupInfo)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP LABEL '%s' %s %s",
+					   backupInfo->backup_label,
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+	PQclear(res);
+}
+
+/*
+ * Retrive backup file list from the server and populate TablespaceInfo struct
+ * to keep track of tablespaces and its files.
+ */
+static void
+GetBackupFileList(PGconn *conn, BackupInfo *backupInfo)
+{
+	int			i;
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	backupInfo->tsInfo = palloc0(sizeof(TablespaceInfo) * backupInfo->tablespacecount);
+	TablespaceInfo *tsInfo = backupInfo->tsInfo;
+
+	/*
+	 * Get list of files.
+	 */
+	basebkp = psprintf("SEND_BACKUP_FILELIST %s",
+					   format == 't' ? "TABLESPACE_MAP" : "");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SEND_BACKUP_FILELIST", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * The list of files is grouped by tablespaces, and we want to fetch them
+	 * in the same order.
+	 */
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		bool		basetablespace;
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tsInfo[i].tblspcOid = atol(PQgetvalue(tablespacehdr, i, 0));
+		tsInfo[i].tablespace = PQgetvalue(tablespacehdr, i, 1);
+		tsInfo[i].numFiles = PQntuples(res);
+		tsInfo[i].backupFiles = palloc0(sizeof(BackupFile) * tsInfo[i].numFiles);
+
+		/* keep count of all files in backup */
+		backupInfo->totalfiles += tsInfo[i].numFiles;
+
+		for (int j = 0; j < tsInfo[i].numFiles; j++)
+		{
+			char	   *path = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+				create_backup_dirs(basetablespace, tsInfo[i].tablespace, path);
+
+			strlcpy(tsInfo[i].backupFiles[j].path, path, MAXPGPATH);
+			tsInfo[i].backupFiles[j].type = type;
+			tsInfo[i].backupFiles[j].size = size;
+			tsInfo[i].backupFiles[j].mtime = mtime;
+			tsInfo[i].backupFiles[j].tsIndex = i;
+		}
+
+		/* sort files in descending order, based on size */
+		qsort(tsInfo[i].backupFiles, tsInfo[i].numFiles,
+			  sizeof(BackupFile), &compareFileSize);
+		PQclear(res);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+}
+
+/*
+ * Retrive and write backup file from the server. The file list is provided by
+ * worker state. It pulls a single file from this list and writes it to the
+ * backup directory.
+ */
+static int
+GetBackupFile(WorkerState *wstate)
+{
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn = NULL;
+	BackupFile *fetchFile = NULL;
+	BackupInfo *backupInfo = NULL;
+
+	backupInfo = wstate->backupInfo;
+	worker_conn = backupInfo->workerConns[wstate->workerid];
+	while ((fetchFile = getNextFile(backupInfo)) != NULL)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+		TablespaceInfo *curTsInfo = &backupInfo->tsInfo[fetchFile->tsIndex];
+
+
+		/*
+		 * build query in form of: SEND_BACKUP_FILES ('base/1/1245/32683',
+		 * 'base/1/1245/32683', ...) [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_BACKUP_FILES ( '%s' )", fetchFile->path);
+
+		/* add options */
+		appendPQExpBuffer(buf, " TABLESPACE_PATH '%s' START_WAL_LOCATION '%s' %s %s",
+						  curTsInfo->tablespace,
+						  backupInfo->xlogstart,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+
+		destroyPQExpBuffer(buf);
+
+		/* process file contents, also count bytesRead for progress */
+		wstate->bytesRead +=
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, fetchFile->tsIndex);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	return 0;
+}
+
+/*
+ * Increment fileIndex and store it in a local variable so that even a
+ * context switch does not affect the file index value and we don't accidentally
+ * increment the value twice and therefore skip some files.
+ */
+static BackupFile*
+getNextFile(BackupInfo *backupInfo)
+{
+	int fileIndex = 0;
+
+	pthread_mutex_lock(&fetch_mutex);
+	fileIndex = backupInfo->fileIndex++;
+	pthread_mutex_unlock(&fetch_mutex);
+
+	if (fileIndex >= backupInfo->totalfiles)
+		return NULL;
+
+	return backupInfo->files[fileIndex];
+}
+
+/* qsort comparator for BackupFile (sort descending order)  */
+static int
+compareFileSize(const void *a, const void *b)
+{
+	const		BackupFile *v1 = (BackupFile *) a;
+	const		BackupFile *v2 = (BackupFile *) b;
+
+	if (v1->size > v2->size)
+		return -1;
+	if (v1->size < v2->size)
+		return 1;
+
+	return 0;
+}
+
+static void
+read_label_tblspcmap(PGconn *conn, char **backuplabel, char **tblspc_map)
+{
+	PGresult   *res = NULL;
+
+	Assert(backuplabel != NULL);
+	Assert(tblspc_map != NULL);
+
+	/*
+	 * Get Backup label and tablespace map data.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) < 1)
+	{
+		pg_log_error("no data returned from server");
+		exit(1);
+	}
+
+	*backuplabel = PQgetvalue(res, 0, 0);	/* backup_label */
+	if (!PQgetisnull(res, 0, 1))
+		*tblspc_map = PQgetvalue(res, 0, 1);	/* tablespace_map */
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	PQclear(res);
+}
+
+/*
+ * Create backup direcotries while taking care of tablespace path. If tablespace
+ * mapping (with -T) is given then the directory will be created on the mapped
+ * path.
+ */
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char	dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+/*
+ * General function for writing to a file; creates one if it doesn't exist
+ */
+static void
+writefile(char *path, char *buf)
+{
+	FILE   *f;
+	char	pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
-- 
2.21.0 (Apple Git-122)

0004-backend-changes-for-parallel-backup_v4.patchapplication/octet-stream; name=0004-backend-changes-for-parallel-backup_v4.patchDownload
From 42818d0ebcdfa119e27e95ed6428cc7026a38143 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 22:59:28 +0500
Subject: [PATCH 4/6] backend changes for parallel backup

---
 src/backend/access/transam/xlog.c      |   2 +-
 src/backend/replication/basebackup.c   | 526 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    |  72 ++++
 src/backend/replication/repl_scanner.l |   7 +
 src/include/nodes/replnodes.h          |  10 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 605 insertions(+), 14 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index aa7d82a045..842b317c8d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -12265,7 +12265,7 @@ collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index b8e3daf711..a0a6e816b0 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -41,6 +41,7 @@
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
+#include "utils/pg_lsn.h"
 
 
 typedef struct
@@ -52,11 +53,21 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	const char *tablespace_path;
+	XLogRecPtr	wal_location;
 } basebackup_options;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
 
 static int64 sendDir(const char *path, int basepathlen, bool dryrun,
-					 List *tablespaces, bool sendtblspclinks);
+					 List *tablespaces, bool sendtblspclinks, List **filelist);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -76,6 +87,13 @@ static void throttle(size_t increment);
 static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendBackupFileList(basebackup_options *opt);
+static void SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok);
+static void addToBackupFileList(List **filelist, char *path, char type, int32 size,
+								time_t mtime);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -290,7 +308,7 @@ perform_base_backup(basebackup_options *opt)
 
 	/* Add a node for the base directory at the end */
 	ti = palloc0(sizeof(tablespaceinfo));
-	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
 	tablespaces = lappend(tablespaces, ti);
 
 	/* Send tablespace header */
@@ -324,10 +342,10 @@ perform_base_backup(basebackup_options *opt)
 			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
 				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-				sendDir(".", 1, false, tablespaces, false);
+				sendDir(".", 1, false, tablespaces, false, NULL);
 			}
 			else
-				sendDir(".", 1, false, tablespaces, true);
+				sendDir(".", 1, false, tablespaces, true, NULL);
 
 			/* ... and pg_control after everything else. */
 			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -338,7 +356,7 @@ perform_base_backup(basebackup_options *opt)
 			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
 		else
-			sendTablespace(ti->path, false);
+			sendTablespace(ti->path, false, NULL);
 
 		/*
 		 * If we're including WAL, and this is the main data directory we
@@ -410,6 +428,8 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_tablespace_path = false;
+	bool		o_wal_location = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -498,6 +518,29 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "tablespace_path") == 0)
+		{
+			if (o_tablespace_path)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+			opt->tablespace_path = strVal(defel->arg);
+			o_tablespace_path = true;
+		}
+		else if (strcmp(defel->defname, "start_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *wal_location;
+
+			if (o_wal_location)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			wal_location = strVal(defel->arg);
+			opt->wal_location = pg_lsn_in_internal(wal_location, &have_error);
+			o_wal_location = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -532,7 +575,29 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_BACKUP_FILELIST:
+			SendBackupFileList(&opt);
+			break;
+		case SEND_BACKUP_FILES:
+			SendBackupFiles(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -675,6 +740,61 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_puttextmessage('C', "SELECT");
 }
 
+/*
+ * Send a single resultset containing backup label and tablespace map
+ */
+static void
+SendStartBackupResult(StringInfo labelfile, StringInfo tblspc_map_file)
+{
+	StringInfoData buf;
+	Size		len;
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);		/* 2 fields */
+
+	/* Field headers */
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "tablespacemap");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint16(&buf, 2);		/* number of columns */
+
+	len = labelfile->len;
+	pq_sendint32(&buf, len);
+	pq_sendbytes(&buf, labelfile->data, len);
+
+	if (tblspc_map_file)
+	{
+		len = tblspc_map_file->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, tblspc_map_file->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
+	}
+
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -726,7 +846,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool dryrun)
+sendTablespace(char *path, bool dryrun, List **filelist)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -755,11 +875,11 @@ sendTablespace(char *path, bool dryrun)
 		return 0;
 	}
 
+	addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   dryrun);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true, filelist);
 
 	return size;
 }
@@ -778,7 +898,7 @@ sendTablespace(char *path, bool dryrun)
  */
 static int64
 sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
-		bool sendtblspclinks)
+		bool sendtblspclinks, List **filelist)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -932,6 +1052,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
@@ -948,6 +1070,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
@@ -969,6 +1093,10 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									dryrun);
 
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
+			addToBackupFileList(filelist, "./pg_wal/archive_status", 'd', -1,
+								statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -998,6 +1126,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			addToBackupFileList(filelist, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, dryrun);
 #else
@@ -1024,6 +1153,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									dryrun);
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1054,13 +1184,15 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks, filelist);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!dryrun)
+			addToBackupFileList(filelist, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!dryrun && filelist == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1765,3 +1897,373 @@ setup_throttle(int maxrate)
 		throttling_counter = -1;
 	}
 }
+
+/*
+ * StartBackup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+	tablespaceinfo *ti;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, register base_backup_cleanup with before_shmem_exit handler. This
+	 * will make sure that call is always made when process exits. In success,
+	 * do_pg_stop_backup will have taken the system out of backup mode and this
+	 * callback will have no effect, Otherwise the required cleanup will be done
+	 * in any case.
+	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
+
+	SendXlogRecPtrResult(startptr, starttli);
+
+	/*
+	 * Calculate the relative path of temporary statistics directory in
+	 * order to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
+	tablespaces = lappend(tablespaces, ti);
+
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
+		!opt->sendtblspcmapfile)
+		tblspc_map_file = NULL;
+
+	/* send backup_label and tablespace_map to frontend */
+	SendStartBackupResult(labelfile, tblspc_map_file);
+}
+
+/*
+ * StopBackup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionaly WAL segments and ending WAL location.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile = NULL;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	/* stop backup */
+	labelfile = (char *) opt->label;
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	if (opt->includewal)
+		include_wal_files(endptr);
+
+	pq_putemptymessage('c');	/* CopyDone */
+	SendXlogRecPtrResult(endptr, endtli);
+}
+
+/*
+ * SendBackupFileList() - sends a list of filenames to frontend
+ *
+ * The function collects a list of filenames, necessary for a complete backup and
+ * sends this list to the client.
+ */
+static void
+SendBackupFileList(basebackup_options *opt)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	List	   *tablespaces = NIL;
+	StringInfo	tblspc_map_file = NULL;
+
+	tblspc_map_file = makeStringInfo();
+	collectTablespaces(&tablespaces, tblspc_map_file, false, false);
+
+	/* Add a node for the base directory at the end */
+	tablespaceinfo *ti = palloc0(sizeof(tablespaceinfo));
+	tablespaces = lappend(tablespaces, ti);
+
+	foreach(lc, tablespaces)
+	{
+		List	   *filelist = NULL;
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+
+		if (ti->path == NULL)
+			sendDir(".", 1, true, NIL, !opt->sendtblspcmapfile, &filelist);
+		else
+			sendTablespace(ti->path, true, &filelist);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 4);	/* n field */
+
+		/* First field - file name */
+		pq_sendstring(&buf, "filename");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "type");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, CHAROID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - mtime */
+		pq_sendstring(&buf, "mtime");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, filelist)
+		{
+			BackupFile *backupFile = (BackupFile *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 4);	/* number of columns */
+
+			/* send file name */
+			len = strlen(backupFile->path);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, backupFile->path, len);
+
+			/* send type */
+			pq_sendint32(&buf, 1);
+			pq_sendbyte(&buf, backupFile->type);
+
+			/* send size */
+			send_int8_string(&buf, backupFile->size);
+
+			/* send mtime */
+			send_int8_string(&buf, backupFile->mtime);
+
+			pq_endmessage(&buf);
+		}
+
+		pfree(filelist);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendBackupFiles() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol.
+ */
+static void
+SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	bool		basetablespace = true;
+	int			basepathlen = 1;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	if (is_absolute_path(opt->tablespace_path))
+	{
+		basepathlen = strlen(opt->tablespace_path);
+		basetablespace = false;
+	}
+
+	/* set backup start location. */
+	startptr = opt->wal_location;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/* Allow symbolic links in pg_tblspc only */
+		if (strstr(pathbuf, "./pg_tblspc") != NULL &&
+#ifndef WIN32
+			S_ISLNK(statbuf.st_mode)
+#else
+			pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			char		linkpath[MAXPGPATH];
+			int			rllen;
+
+			rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not read symbolic link \"%s\": %m",
+								pathbuf)));
+			if (rllen >= sizeof(linkpath))
+				ereport(ERROR,
+						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+						 errmsg("symbolic link \"%s\" target is too long",
+								pathbuf)));
+			linkpath[rllen] = '\0';
+
+			_tarWriteHeader(pathbuf, linkpath, &statbuf, false);
+		}
+		else if (S_ISDIR(statbuf.st_mode))
+		{
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else if (
+#ifndef WIN32
+				 S_ISLNK(statbuf.st_mode)
+#else
+				 pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			/*
+			 * If symlink, write it as a directory. file symlinks only allowed
+			 * in pg_tblspc
+			 */
+			statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report total checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+/*
+ * Construct a BackupFile entry and add to the list.
+ */
+static void
+addToBackupFileList(List **filelist,  char *path, char type, int32 size,
+					time_t mtime)
+{
+	BackupFile *backupFile;
+
+	if (filelist)
+	{
+		backupFile = (BackupFile *) palloc0(sizeof(BackupFile));
+		strlcpy(backupFile->path, path, sizeof(backupFile->path));
+		backupFile->type = type;
+		backupFile->size = size;
+		backupFile->mtime = mtime;
+
+		*filelist = lappend(*filelist, backupFile);
+	}
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..5619837ebe 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,6 +87,12 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_BACKUP_FILELIST
+%token K_SEND_BACKUP_FILES
+%token K_STOP_BACKUP
+%token K_START_WAL_LOCATION
+%token K_TABLESPACE_PATH
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
@@ -102,6 +108,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -162,6 +170,36 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_START_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_FILELIST base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = SEND_BACKUP_FILELIST;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_FILES backup_files base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_BACKUP_FILES;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP base_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
@@ -214,6 +252,40 @@ base_backup_opt:
 				  $$ = makeDefElem("noverify_checksums",
 								   (Node *)makeInteger(true), -1);
 				}
+			| K_START_WAL_LOCATION SCONST
+				{
+				  $$ = makeDefElem("start_wal_location",
+								   (Node *)makeString($2), -1);
+				}
+			| K_TABLESPACE_PATH SCONST
+				{
+				  $$ = makeDefElem("tablespace_path",
+								   (Node *)makeString($2), -1);
+				}
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{
+					$$ = $2;
+				}
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
+				{
+					$$ = list_make1($1);
+				}
+			| backup_files_list ',' backup_file
+				{
+					$$ = lappend($1, $3);
+				}
+			;
+
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
 			;
 
 create_replication_slot:
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..c57ff02d39 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,13 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_BACKUP_FILELIST	{ return K_SEND_BACKUP_FILELIST; }
+SEND_BACKUP_FILES	{ return K_SEND_BACKUP_FILES; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
+TABLESPACE_PATH		{ return K_TABLESPACE_PATH; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..3685f260b5 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,14 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_BACKUP_FILELIST,
+	SEND_BACKUP_FILES,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +50,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index b55917b9b6..5202e4160b 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool dryrun);
+extern int64 sendTablespace(char *path, bool dryrun, List **filelist);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122)

0003-Refactor-some-basebackup-code-to-increase-reusabilit_v4.patchapplication/octet-stream; name=0003-Refactor-some-basebackup-code-to-increase-reusabilit_v4.patchDownload
From 21866fd73f852c4064c3e588f62964fe1bd52440 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 9 Oct 2019 12:39:41 +0500
Subject: [PATCH 3/6] Refactor some basebackup code to increase reusability, in
 anticipation of adding parallel backup

---
 src/backend/access/transam/xlog.c    | 192 +++++-----
 src/backend/replication/basebackup.c | 512 ++++++++++++++-------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 371 insertions(+), 335 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 2e3cc51006..aa7d82a045 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10286,10 +10286,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10415,93 +10411,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collectTablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12277,3 +12187,103 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+				   bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to
+		 * ensure that we can distinguish between the newline in the
+		 * tablespace path and end of line while reading tablespace_map
+		 * file during archive recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory
+		 * when it's located within PGDATA, or NULL if it's located
+		 * elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created
+		 * them. Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 9442486b66..b8e3daf711 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -68,10 +68,12 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt);
+static void include_wal_files(XLogRecPtr endptr);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
+static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
@@ -294,29 +296,7 @@ perform_base_backup(basebackup_options *opt)
 	/* Send tablespace header */
 	SendBackupHeader(tablespaces);
 
-	/* Setup and activate network throttling, if client requested it */
-	if (opt->maxrate > 0)
-	{
-		throttling_sample =
-			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-		/*
-		 * The minimum amount of time for throttling_sample bytes to be
-		 * transferred.
-		 */
-		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-		/* Enable throttling. */
-		throttling_counter = 0;
-
-		/* The 'real data' starts now (header was ignored). */
-		throttled_last = GetCurrentTimestamp();
-	}
-	else
-	{
-		/* Disable throttling. */
-		throttling_counter = -1;
-	}
+	setup_throttle(opt->maxrate);
 
 	/* Send off our tablespaces one by one */
 	foreach(lc, tablespaces)
@@ -382,227 +362,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -1741,3 +1501,267 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * Append the required WAL files to the backup tar file. It assumes that the
+ * last tar file is "open" and the WALs will be appended to it.
+ */
+static void
+include_wal_files(XLogRecPtr endptr)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the
+	 * required WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and
+	 * include all WAL files in the range between 'startptr' and 'endptr',
+	 * regardless of the timeline the file is stamped with. If there are
+	 * some spurious WAL files belonging to timelines that don't belong in
+	 * this server's history, they will be included too. Normally there
+	 * shouldn't be such files, but if there are, there's little harm in
+	 * including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we
+	 * need were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from
+	 * oldest to newest, to reduce the chance that a file is recycled
+	 * before we get a chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since
+	 * we are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		CHECK_FREAD_ERROR(fp, pathbuf);
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again
+		 * after promotion of a new node. This is in line with
+		 * walreceiver.c always doing an XLogArchiveForceDone() after a
+		 * complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history
+	 * file is required for recovery, and even that only if there happens
+	 * to be a timeline switch in the first WAL segment that contains the
+	 * checkpoint record, or if we're taking a base backup from a standby
+	 * server and the target timeline changes while the backup is taken.
+	 * But they are small and highly useful for debugging purposes, so
+	 * better include them all, always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d519252aad..5b0aa8ae85 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 									 bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
+extern void collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+							   bool infotbssize, bool needtblspcmapfile);
 extern void do_pg_abort_backup(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.0 (Apple Git-122)

0006-parallel-backup-testcase_v4.patchapplication/octet-stream; name=0006-parallel-backup-testcase_v4.patchDownload
From 0ce590c1a4027408989988a74f9e7d45bbeb8875 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 6/6] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 527 ++++++++++++++++++
 1 file changed, 527 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..4ec4c1e0f6
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,527 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 95;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+#	# Create a temporary directory in the system location and symlink it
+#	# to our physical temp location.  That way we can use shorter names
+#	# for the tablespace directories, which hopefully won't run afoul of
+#	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+my $file;
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.0 (Apple Git-122)

#31Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#29)
Re: WIP/PoC for parallel backup

On Wed, Oct 30, 2019 at 10:16 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

'startptr' is used by sendFile() during checksum verification. Since
SendBackupFiles() is using sendFIle we have to set a valid WAL location.

Ugh, global variables.

Why are START_BACKUP, SEND_BACKUP_FILELIST, SEND_BACKUP_FILES, and
STOP_BACKUP all using the same base_backup_opt_list production as
BASE_BACKUP? Presumably most of those options are not applicable to
most of those commands, and the productions should therefore be
separated.

You should add docs, too. I wouldn't have to guess what some of this
stuff was for if you wrote documentation explaining what this stuff
was for. :-)

The tablespace_path option appears entirely unused, and I don't know
why that should be necessary here, either.

This is to calculate the basepathlen. We need to exclude the tablespace location (or
base path) from the filename before it is sent to the client with sendFile call. I added
this option primarily to avoid performing string manipulation on filename to extract the
tablespace location and then calculate the basepathlen.

Alternatively we can do it by extracting the base path from the received filename. What
do you suggest?

I don't think the server needs any information from the client in
order to be able to exclude the tablespace location from the pathname.
Whatever it needs to know, it should be able to figure out, just as it
would in a non-parallel backup.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#32Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#31)
1 attachment(s)
Re: WIP/PoC for parallel backup

On Fri, Nov 1, 2019 at 8:53 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Oct 30, 2019 at 10:16 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

'startptr' is used by sendFile() during checksum verification. Since
SendBackupFiles() is using sendFIle we have to set a valid WAL location.

Ugh, global variables.

Why are START_BACKUP, SEND_BACKUP_FILELIST, SEND_BACKUP_FILES, and
STOP_BACKUP all using the same base_backup_opt_list production as
BASE_BACKUP? Presumably most of those options are not applicable to
most of those commands, and the productions should therefore be
separated.

Are you expecting something like the attached patch? Basically I have
reorganised the grammar
rules so each command can have the options required by it.

I was feeling a bit reluctant for this change because it may add some
unwanted grammar rules in
the replication grammar. Since these commands are using the same options as
base backup, may
be we could throw error inside the relevant functions on unwanted options?

You should add docs, too. I wouldn't have to guess what some of this
stuff was for if you wrote documentation explaining what this stuff
was for. :-)

Yes I will add it in the next patch.

The tablespace_path option appears entirely unused, and I don't know
why that should be necessary here, either.

This is to calculate the basepathlen. We need to exclude the tablespace

location (or

base path) from the filename before it is sent to the client with

sendFile call. I added

this option primarily to avoid performing string manipulation on

filename to extract the

tablespace location and then calculate the basepathlen.

Alternatively we can do it by extracting the base path from the received

filename. What

do you suggest?

I don't think the server needs any information from the client in
order to be able to exclude the tablespace location from the pathname.
Whatever it needs to know, it should be able to figure out, just as it
would in a non-parallel backup.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

repl_grammar.patchapplication/octet-stream; name=repl_grammar.patchDownload
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index 5619837ebe..f94961132e 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -99,7 +99,13 @@ static SQLCmd *make_sqlcmd(void);
 				create_replication_slot drop_replication_slot identify_system
 				timeline_history show sql_cmd
 %type <list>	base_backup_opt_list
+				start_backup_opt_list stop_backup_opt_list
+				send_backup_files_opt_list send_backup_filelist
 %type <defelt>	base_backup_opt
+				backup_opt_label backup_opt_progress backup_opt_maxrate
+				backup_opt_fast backup_opt_tsmap backup_opt_wal backup_opt_nowait
+				backup_opt_chksum backup_opt_wal_loc backup_opt_tspath
+				start_backup_opt stop_backup_opt send_backup_filelist_opt send_backup_files_opt
 %type <uintval>	opt_timeline
 %type <list>	plugin_options plugin_opt_list
 %type <defelt>	plugin_opt_elem
@@ -173,21 +179,21 @@ base_backup:
 					cmd->cmdtag = BASE_BACKUP;
 					$$ = (Node *) cmd;
 				}
-			| K_START_BACKUP base_backup_opt_list
+			| K_START_BACKUP start_backup_opt_list
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
 					cmd->cmdtag = START_BACKUP;
 					$$ = (Node *) cmd;
 				}
-			| K_SEND_BACKUP_FILELIST base_backup_opt_list
+			| K_SEND_BACKUP_FILELIST send_backup_filelist
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
 					cmd->cmdtag = SEND_BACKUP_FILELIST;
 					$$ = (Node *) cmd;
 				}
-			| K_SEND_BACKUP_FILES backup_files base_backup_opt_list
+			| K_SEND_BACKUP_FILES backup_files send_backup_files_opt_list
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $3;
@@ -195,7 +201,7 @@ base_backup:
 					cmd->backupfiles = $2;
 					$$ = (Node *) cmd;
 				}
-			| K_STOP_BACKUP base_backup_opt_list
+			| K_STOP_BACKUP stop_backup_opt_list
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
@@ -204,6 +210,34 @@ base_backup:
 				}
 			;
 
+start_backup_opt_list:
+	start_backup_opt_list start_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+			;
+
+stop_backup_opt_list:
+	stop_backup_opt_list stop_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
+send_backup_filelist:
+	send_backup_filelist send_backup_filelist_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
+send_backup_files_opt_list:
+	send_backup_files_opt_list send_backup_files_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
 base_backup_opt_list:
 			base_backup_opt_list base_backup_opt
 				{ $$ = lappend($1, $2); }
@@ -211,59 +245,114 @@ base_backup_opt_list:
 				{ $$ = NIL; }
 			;
 
+start_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_maxrate	{ $$ = $1; }
+		| backup_opt_progress	{ $$ = $1; }
+		| backup_opt_tsmap		{ $$ = $1; }
+			;
+
+stop_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_maxrate	{ $$ = $1; }
+		| backup_opt_wal 		{ $$ = $1; }
+		| backup_opt_nowait		{ $$ = $1; }
+			;
+
+send_backup_filelist_opt:
+		backup_opt_tsmap		{ $$ = $1; }
+			;
+
+send_backup_files_opt:
+			backup_opt_maxrate		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_wal_loc	{ $$ = $1; }
+			| backup_opt_tspath		{ $$ = $1; }
+			;
+
 base_backup_opt:
-			K_LABEL SCONST
-				{
-				  $$ = makeDefElem("label",
-								   (Node *)makeString($2), -1);
-				}
-			| K_PROGRESS
-				{
-				  $$ = makeDefElem("progress",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_FAST
-				{
-				  $$ = makeDefElem("fast",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_WAL
-				{
-				  $$ = makeDefElem("wal",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_NOWAIT
-				{
-				  $$ = makeDefElem("nowait",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_MAX_RATE UCONST
-				{
-				  $$ = makeDefElem("max_rate",
-								   (Node *)makeInteger($2), -1);
-				}
-			| K_TABLESPACE_MAP
-				{
-				  $$ = makeDefElem("tablespace_map",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_NOVERIFY_CHECKSUMS
-				{
-				  $$ = makeDefElem("noverify_checksums",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_START_WAL_LOCATION SCONST
-				{
-				  $$ = makeDefElem("start_wal_location",
-								   (Node *)makeString($2), -1);
-				}
-			| K_TABLESPACE_PATH SCONST
-				{
-				  $$ = makeDefElem("tablespace_path",
-								   (Node *)makeString($2), -1);
-				}
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_maxrate	{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			| backup_opt_progress	{ $$ = $1; }
+			| backup_opt_tsmap		{ $$ = $1; }
+			| backup_opt_wal 		{ $$ = $1; }
+			| backup_opt_nowait		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_wal_loc	{ $$ = $1; }
+			| backup_opt_tspath		{ $$ = $1; }
 			;
 
+backup_opt_label:
+	K_LABEL SCONST
+	{
+	  $$ = makeDefElem("label",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_progress:
+	K_PROGRESS
+	{
+	  $$ = makeDefElem("progress",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_fast:
+	K_FAST
+	{
+	  $$ = makeDefElem("fast",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal:
+	K_WAL
+	{
+	  $$ = makeDefElem("wal",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_nowait:
+	K_NOWAIT
+	{
+	  $$ = makeDefElem("nowait",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_maxrate:
+	K_MAX_RATE UCONST
+	{
+	  $$ = makeDefElem("max_rate",
+					   (Node *)makeInteger($2), -1);
+	};
+
+backup_opt_tsmap:
+	K_TABLESPACE_MAP
+	{
+	  $$ = makeDefElem("tablespace_map",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_chksum:
+	K_NOVERIFY_CHECKSUMS
+	{
+	  $$ = makeDefElem("noverify_checksums",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal_loc:
+	K_START_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("start_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_tspath:
+	K_TABLESPACE_PATH SCONST
+	{
+	  $$ = makeDefElem("tablespace_path",
+					   (Node *)makeString($2), -1);
+	};
+
 backup_files:
 			'(' backup_files_list ')'
 				{
#33Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#32)
7 attachment(s)
Re: WIP/PoC for parallel backup

On Mon, Nov 4, 2019 at 6:08 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Fri, Nov 1, 2019 at 8:53 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Oct 30, 2019 at 10:16 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

'startptr' is used by sendFile() during checksum verification. Since
SendBackupFiles() is using sendFIle we have to set a valid WAL location.

Ugh, global variables.

Why are START_BACKUP, SEND_BACKUP_FILELIST, SEND_BACKUP_FILES, and
STOP_BACKUP all using the same base_backup_opt_list production as
BASE_BACKUP? Presumably most of those options are not applicable to
most of those commands, and the productions should therefore be
separated.

Are you expecting something like the attached patch? Basically I have
reorganised the grammar
rules so each command can have the options required by it.

I was feeling a bit reluctant for this change because it may add some
unwanted grammar rules in
the replication grammar. Since these commands are using the same options
as base backup, may
be we could throw error inside the relevant functions on unwanted options?

You should add docs, too. I wouldn't have to guess what some of this
stuff was for if you wrote documentation explaining what this stuff
was for. :-)

Yes I will add it in the next patch.

The tablespace_path option appears entirely unused, and I don't know
why that should be necessary here, either.

This is to calculate the basepathlen. We need to exclude the tablespace

location (or

base path) from the filename before it is sent to the client with

sendFile call. I added

this option primarily to avoid performing string manipulation on

filename to extract the

tablespace location and then calculate the basepathlen.

Alternatively we can do it by extracting the base path from the

received filename. What

do you suggest?

I don't think the server needs any information from the client in
order to be able to exclude the tablespace location from the pathname.
Whatever it needs to know, it should be able to figure out, just as it
would in a non-parallel backup.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

I have updated the replication grammar with some new rules to differentiate
the options production
for base backup and newly added commands.

I have also created a separate patch to include the documentation changes.
The current syntax is as below:

- START_BACKUP [ LABEL 'label' ] [ PROGRESS ] [ FAST ] [ TABLESPACE_MAP ]
- STOP_BACKUP [ LABEL 'label' ] [ WAL ] [ NOWAIT ]
- SEND_BACKUP_FILELIST
- SEND_BACKUP_FILES ( 'FILE' [, ...] ) [ MAX_RATE rate ] [
NOVERIFY_CHECKSUMS ] [ START_WAL_LOCATION ]

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0004-backend-changes-for-parallel-backup.patchapplication/octet-stream; name=0004-backend-changes-for-parallel-backup.patchDownload
From 2f71ddec4a9e75538af61aafc1a5bc85642d4139 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 22:59:28 +0500
Subject: [PATCH 4/7] backend changes for parallel backup

---
 src/backend/access/transam/xlog.c      |   2 +-
 src/backend/replication/basebackup.c   | 552 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    | 217 ++++++++--
 src/backend/replication/repl_scanner.l |   7 +
 src/include/nodes/replnodes.h          |  10 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 740 insertions(+), 50 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 451fe6c0d1..445aad291e 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -12279,7 +12279,7 @@ collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index b679f36021..57e0b7a0ab 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -41,6 +41,7 @@
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
+#include "utils/pg_lsn.h"
 
 typedef struct
 {
@@ -51,11 +52,21 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	const char *tablespace_path;
+	XLogRecPtr	wal_location;
 } basebackup_options;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
 
 static int64 sendDir(const char *path, int basepathlen, bool dryrun,
-					 List *tablespaces, bool sendtblspclinks);
+					 List *tablespaces, bool sendtblspclinks, List **filelist);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -75,6 +86,13 @@ static void throttle(size_t increment);
 static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendBackupFileList(void);
+static void SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok);
+static void addToBackupFileList(List **filelist, char *path, char type, int32 size,
+								time_t mtime);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -289,7 +307,7 @@ perform_base_backup(basebackup_options *opt)
 
 	/* Add a node for the base directory at the end */
 	ti = palloc0(sizeof(tablespaceinfo));
-	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
 	tablespaces = lappend(tablespaces, ti);
 
 	/* Send tablespace header */
@@ -323,10 +341,10 @@ perform_base_backup(basebackup_options *opt)
 			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
 				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-				sendDir(".", 1, false, tablespaces, false);
+				sendDir(".", 1, false, tablespaces, false, NULL);
 			}
 			else
-				sendDir(".", 1, false, tablespaces, true);
+				sendDir(".", 1, false, tablespaces, true, NULL);
 
 			/* ... and pg_control after everything else. */
 			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -337,7 +355,7 @@ perform_base_backup(basebackup_options *opt)
 			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
 		else
-			sendTablespace(ti->path, false);
+			sendTablespace(ti->path, false, NULL);
 
 		/*
 		 * If we're including WAL, and this is the main data directory we
@@ -409,6 +427,8 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_tablespace_path = false;
+	bool		o_wal_location = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -497,12 +517,33 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "tablespace_path") == 0)
+		{
+			if (o_tablespace_path)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+			opt->tablespace_path = strVal(defel->arg);
+			o_tablespace_path = true;
+		}
+		else if (strcmp(defel->defname, "start_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *wal_location;
+
+			if (o_wal_location)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			wal_location = strVal(defel->arg);
+			opt->wal_location = pg_lsn_in_internal(wal_location, &have_error);
+			o_wal_location = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
 	}
-	if (opt->label == NULL)
-		opt->label = "base backup";
 }
 
 
@@ -520,6 +561,15 @@ SendBaseBackup(BaseBackupCmd *cmd)
 
 	parse_basebackup_options(cmd->options, &opt);
 
+	/* default value for label, if not specified. */
+	if (opt.label == NULL)
+	{
+		if (cmd->cmdtag == BASE_BACKUP)
+			opt.label = "base backup";
+		else
+			opt.label = "start backup";
+	}
+
 	WalSndSetState(WALSNDSTATE_BACKUP);
 
 	if (update_process_title)
@@ -531,7 +581,29 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_BACKUP_FILELIST:
+			SendBackupFileList();
+			break;
+		case SEND_BACKUP_FILES:
+			SendBackupFiles(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -674,6 +746,61 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_puttextmessage('C', "SELECT");
 }
 
+/*
+ * Send a single resultset containing backup label and tablespace map
+ */
+static void
+SendStartBackupResult(StringInfo labelfile, StringInfo tblspc_map_file)
+{
+	StringInfoData buf;
+	Size		len;
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);		/* 2 fields */
+
+	/* Field headers */
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "tablespacemap");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint16(&buf, 2);		/* number of columns */
+
+	len = labelfile->len;
+	pq_sendint32(&buf, len);
+	pq_sendbytes(&buf, labelfile->data, len);
+
+	if (tblspc_map_file)
+	{
+		len = tblspc_map_file->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, tblspc_map_file->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
+	}
+
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -725,7 +852,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool dryrun)
+sendTablespace(char *path, bool dryrun, List **filelist)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -754,11 +881,11 @@ sendTablespace(char *path, bool dryrun)
 		return 0;
 	}
 
+	addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   dryrun);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true, filelist);
 
 	return size;
 }
@@ -777,7 +904,7 @@ sendTablespace(char *path, bool dryrun)
  */
 static int64
 sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
-		bool sendtblspclinks)
+		bool sendtblspclinks, List **filelist)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -931,6 +1058,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
@@ -947,6 +1076,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
@@ -968,6 +1099,10 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									dryrun);
 
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
+			addToBackupFileList(filelist, "./pg_wal/archive_status", 'd', -1,
+								statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -997,6 +1132,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			addToBackupFileList(filelist, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, dryrun);
 #else
@@ -1023,6 +1159,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									dryrun);
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1053,13 +1190,15 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks, filelist);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!dryrun)
+			addToBackupFileList(filelist, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!dryrun && filelist == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1764,3 +1903,388 @@ setup_throttle(int maxrate)
 		throttling_counter = -1;
 	}
 }
+
+/*
+ * StartBackup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+	tablespaceinfo *ti;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, register base_backup_cleanup with before_shmem_exit handler. This
+	 * will make sure that call is always made when process exits. In success,
+	 * do_pg_stop_backup will have taken the system out of backup mode and this
+	 * callback will have no effect, Otherwise the required cleanup will be done
+	 * in any case.
+	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
+
+	SendXlogRecPtrResult(startptr, starttli);
+
+	/*
+	 * Calculate the relative path of temporary statistics directory in
+	 * order to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
+	tablespaces = lappend(tablespaces, ti);
+
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
+		!opt->sendtblspcmapfile)
+		tblspc_map_file = NULL;
+
+	/* send backup_label and tablespace_map to frontend */
+	SendStartBackupResult(labelfile, tblspc_map_file);
+}
+
+/*
+ * StopBackup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionaly WAL segments and ending WAL location.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile = NULL;
+
+	if (get_backup_status() != SESSION_BACKUP_NON_EXCLUSIVE)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("non-exclusive backup is not in progress")));
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	/* stop backup */
+	labelfile = (char *) opt->label;
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	if (opt->includewal)
+		include_wal_files(endptr);
+
+	pq_putemptymessage('c');	/* CopyDone */
+	SendXlogRecPtrResult(endptr, endtli);
+}
+
+/*
+ * SendBackupFileList() - sends a list of filenames to frontend
+ *
+ * The function collects a list of filenames, necessary for a complete backup and
+ * sends this list to the client.
+ */
+static void
+SendBackupFileList(void)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	List	   *tablespaces = NIL;
+	StringInfo	tblspc_map_file = NULL;
+	tablespaceinfo *ti;
+
+	tblspc_map_file = makeStringInfo();
+	collectTablespaces(&tablespaces, tblspc_map_file, false, false);
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	tablespaces = lappend(tablespaces, ti);
+
+	foreach(lc, tablespaces)
+	{
+		List	   *filelist = NULL;
+		tablespaceinfo *ti;
+
+		ti = (tablespaceinfo *) lfirst(lc);
+		if (ti->path == NULL)
+			sendDir(".", 1, true, NIL, true, &filelist);
+		else
+			sendTablespace(ti->path, true, &filelist);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 4);	/* n field */
+
+		/* First field - file name */
+		pq_sendstring(&buf, "path");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "type");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, CHAROID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - mtime */
+		pq_sendstring(&buf, "mtime");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, filelist)
+		{
+			BackupFile *backupFile = (BackupFile *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 4);	/* number of columns */
+
+			/* send path */
+			len = strlen(backupFile->path);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, backupFile->path, len);
+
+			/* send type */
+			pq_sendint32(&buf, 1);
+			pq_sendbyte(&buf, backupFile->type);
+
+			/* send size */
+			send_int8_string(&buf, backupFile->size);
+
+			/* send mtime */
+			send_int8_string(&buf, backupFile->mtime);
+
+			pq_endmessage(&buf);
+		}
+
+		if (filelist)
+			pfree(filelist);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendBackupFiles() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol.
+ */
+static void
+SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	int			basepathlen = 1;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/* set backup start location. */
+	startptr = opt->wal_location;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (is_absolute_path(pathbuf))
+		{
+			char *basepath;
+
+			/*
+			 * 'pathbuf' points to the tablespace location, but we only want to
+			 * include the version directory in it that belongs to us.
+			 */
+			basepath = strstr(pathbuf, TABLESPACE_VERSION_DIRECTORY);
+			if (basepath)
+				basepathlen  = basepath - pathbuf - 1;
+		}
+
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/* Allow symbolic links in pg_tblspc only */
+		if (strstr(pathbuf, "./pg_tblspc") != NULL &&
+#ifndef WIN32
+			S_ISLNK(statbuf.st_mode)
+#else
+			pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			char		linkpath[MAXPGPATH];
+			int			rllen;
+
+			rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not read symbolic link \"%s\": %m",
+								pathbuf)));
+			if (rllen >= sizeof(linkpath))
+				ereport(ERROR,
+						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+						 errmsg("symbolic link \"%s\" target is too long",
+								pathbuf)));
+			linkpath[rllen] = '\0';
+
+			_tarWriteHeader(pathbuf, linkpath, &statbuf, false);
+		}
+		else if (S_ISDIR(statbuf.st_mode))
+		{
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else if (
+#ifndef WIN32
+				 S_ISLNK(statbuf.st_mode)
+#else
+				 pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			/*
+			 * If symlink, write it as a directory. file symlinks only allowed
+			 * in pg_tblspc
+			 */
+			statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report total checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+/*
+ * Construct a BackupFile entry and add to the list.
+ */
+static void
+addToBackupFileList(List **filelist,  char *path, char type, int32 size,
+					time_t mtime)
+{
+	BackupFile *backupFile;
+
+	if (filelist)
+	{
+		backupFile = (BackupFile *) palloc0(sizeof(BackupFile));
+		strlcpy(backupFile->path, path, sizeof(backupFile->path));
+		backupFile->type = type;
+		backupFile->size = size;
+		backupFile->mtime = mtime;
+
+		*filelist = lappend(*filelist, backupFile);
+	}
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..9a652ff556 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,13 +87,25 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_BACKUP_FILELIST
+%token K_SEND_BACKUP_FILES
+%token K_STOP_BACKUP
+%token K_START_WAL_LOCATION
+%token K_TABLESPACE_PATH
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
 				create_replication_slot drop_replication_slot identify_system
 				timeline_history show sql_cmd
 %type <list>	base_backup_opt_list
+				start_backup_opt_list stop_backup_opt_list
+				send_backup_files_opt_list
 %type <defelt>	base_backup_opt
+				backup_opt_label backup_opt_progress backup_opt_maxrate
+				backup_opt_fast backup_opt_tsmap backup_opt_wal backup_opt_nowait
+				backup_opt_chksum backup_opt_wal_loc backup_opt_tspath
+				start_backup_opt stop_backup_opt send_backup_files_opt
 %type <uintval>	opt_timeline
 %type <list>	plugin_options plugin_opt_list
 %type <defelt>	plugin_opt_elem
@@ -102,6 +114,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -162,10 +176,61 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
 					$$ = (Node *) cmd;
 				}
+			| K_START_BACKUP start_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_FILELIST
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = NIL;
+					cmd->cmdtag = SEND_BACKUP_FILELIST;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_FILES backup_files send_backup_files_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_BACKUP_FILES;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP stop_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			;
+
+start_backup_opt_list:
+	start_backup_opt_list start_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
 			;
 
+stop_backup_opt_list:
+	stop_backup_opt_list stop_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
+send_backup_files_opt_list:
+	send_backup_files_opt_list send_backup_files_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
 base_backup_opt_list:
 			base_backup_opt_list base_backup_opt
 				{ $$ = lappend($1, $2); }
@@ -173,49 +238,133 @@ base_backup_opt_list:
 				{ $$ = NIL; }
 			;
 
+start_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_fast		{ $$ = $1; }
+		| backup_opt_progress	{ $$ = $1; }
+		| backup_opt_tsmap		{ $$ = $1; }
+			;
+
+stop_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_wal 		{ $$ = $1; }
+		| backup_opt_nowait		{ $$ = $1; }
+			;
+
+send_backup_files_opt:
+			backup_opt_maxrate		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_wal_loc	{ $$ = $1; }
+			| backup_opt_tspath		{ $$ = $1; }
+			;
+
 base_backup_opt:
-			K_LABEL SCONST
-				{
-				  $$ = makeDefElem("label",
-								   (Node *)makeString($2), -1);
-				}
-			| K_PROGRESS
-				{
-				  $$ = makeDefElem("progress",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_FAST
-				{
-				  $$ = makeDefElem("fast",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_WAL
-				{
-				  $$ = makeDefElem("wal",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_NOWAIT
-				{
-				  $$ = makeDefElem("nowait",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_MAX_RATE UCONST
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_maxrate	{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			| backup_opt_progress	{ $$ = $1; }
+			| backup_opt_tsmap		{ $$ = $1; }
+			| backup_opt_wal 		{ $$ = $1; }
+			| backup_opt_nowait		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_wal_loc	{ $$ = $1; }
+			| backup_opt_tspath		{ $$ = $1; }
+			;
+
+backup_opt_label:
+	K_LABEL SCONST
+	{
+	  $$ = makeDefElem("label",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_progress:
+	K_PROGRESS
+	{
+	  $$ = makeDefElem("progress",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_fast:
+	K_FAST
+	{
+	  $$ = makeDefElem("fast",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal:
+	K_WAL
+	{
+	  $$ = makeDefElem("wal",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_nowait:
+	K_NOWAIT
+	{
+	  $$ = makeDefElem("nowait",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_maxrate:
+	K_MAX_RATE UCONST
+	{
+	  $$ = makeDefElem("max_rate",
+					   (Node *)makeInteger($2), -1);
+	};
+
+backup_opt_tsmap:
+	K_TABLESPACE_MAP
+	{
+	  $$ = makeDefElem("tablespace_map",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_chksum:
+	K_NOVERIFY_CHECKSUMS
+	{
+	  $$ = makeDefElem("noverify_checksums",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal_loc:
+	K_START_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("start_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_tspath:
+	K_TABLESPACE_PATH SCONST
+	{
+	  $$ = makeDefElem("tablespace_path",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_files:
+			'(' backup_files_list ')'
 				{
-				  $$ = makeDefElem("max_rate",
-								   (Node *)makeInteger($2), -1);
+					$$ = $2;
 				}
-			| K_TABLESPACE_MAP
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
 				{
-				  $$ = makeDefElem("tablespace_map",
-								   (Node *)makeInteger(true), -1);
+					$$ = list_make1($1);
 				}
-			| K_NOVERIFY_CHECKSUMS
+			| backup_files_list ',' backup_file
 				{
-				  $$ = makeDefElem("noverify_checksums",
-								   (Node *)makeInteger(true), -1);
+					$$ = lappend($1, $3);
 				}
 			;
 
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
+			;
+
 create_replication_slot:
 			/* CREATE_REPLICATION_SLOT slot TEMPORARY PHYSICAL RESERVE_WAL */
 			K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL create_slot_opt_list
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..c57ff02d39 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,13 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_BACKUP_FILELIST	{ return K_SEND_BACKUP_FILELIST; }
+SEND_BACKUP_FILES	{ return K_SEND_BACKUP_FILES; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
+TABLESPACE_PATH		{ return K_TABLESPACE_PATH; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..3685f260b5 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,14 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_BACKUP_FILELIST,
+	SEND_BACKUP_FILES,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +50,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index b55917b9b6..5202e4160b 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool dryrun);
+extern int64 sendTablespace(char *path, bool dryrun, List **filelist);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122.2)

0005-pg_basebackup-changes-for-parallel-backup.patchapplication/octet-stream; name=0005-pg_basebackup-changes-for-parallel-backup.patchDownload
From 6e55a5e2ee030b204c80ca575e0647b44c698310 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 14 Oct 2019 17:28:58 +0500
Subject: [PATCH 5/7] pg_basebackup changes for parallel backup.

---
 src/bin/pg_basebackup/pg_basebackup.c | 737 ++++++++++++++++++++++++--
 1 file changed, 690 insertions(+), 47 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index a9d162a7da..41dba42f06 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -19,6 +19,7 @@
 #include <sys/wait.h>
 #include <signal.h>
 #include <time.h>
+#include <pthread.h>
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -41,6 +42,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -57,6 +59,57 @@ typedef struct TablespaceList
 	TablespaceListCell *tail;
 } TablespaceList;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+
+	int			tsIndex;	/* index of tsInfo this file belongs to. */
+} BackupFile;
+
+typedef struct
+{
+	Oid			tblspcOid;
+	char	   *tablespace;	 /* tablespace name or NULL if 'base' tablespace */
+	int			numFiles;	 /* number of files */
+	BackupFile *backupFiles; /* list of files in a tablespace */
+} TablespaceInfo;
+
+typedef struct
+{
+	int 	tablespacecount;
+	int		totalfiles;
+	int		numWorkers;
+
+	char	xlogstart[64];
+	char   *backup_label;
+	char   *tablespace_map;
+
+	TablespaceInfo *tsInfo;
+	BackupFile	  **files;		/* list of BackupFile pointers */
+	int				fileIndex;	/* index of file to be fetched */
+
+	PGconn	**workerConns;
+} BackupInfo;
+
+typedef struct
+{
+	BackupInfo *backupInfo;
+	uint64		bytesRead;
+
+	int			workerid;
+	pthread_t	worker;
+
+	bool	terminated;
+} WorkerState;
+
+BackupInfo *backupInfo = NULL;
+WorkerState *workers = NULL;
+
+static pthread_mutex_t fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -110,6 +163,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -140,9 +196,10 @@ static PQExpBuffer recoveryconfcontents = NULL;
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
+static void workers_progress_report(uint64 totalBytesRead, const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
-static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
+static int	ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
 
 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -151,6 +208,17 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupRun(BackupInfo *backupInfo);
+static void StopBackup(BackupInfo *backupInfo);
+static void GetBackupFileList(PGconn *conn, BackupInfo *backupInfo);
+static int GetBackupFile(WorkerState *wstate);
+static BackupFile *getNextFile(BackupInfo *backupInfo);
+static int	compareFileSize(const void *a, const void *b);
+static void read_label_tblspcmap(PGconn *conn, char **backup_label, char **tablespace_map);
+static void create_backup_dirs(bool basetablespace, char *tablespace, char *name);
+static void writefile(char *path, char *buf);
+static void *workerRun(void *arg);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -202,6 +270,17 @@ cleanup_directories_atexit(void)
 static void
 disconnect_atexit(void)
 {
+	/* close worker connections */
+	if (backupInfo && backupInfo->workerConns != NULL)
+	{
+		int i;
+		for (i = 0; i < numWorkers; i++)
+		{
+			if (backupInfo->workerConns[i] != NULL)
+				PQfinish(backupInfo->workerConns[i]);
+		}
+	}
+
 	if (conn != NULL)
 		PQfinish(conn);
 }
@@ -349,6 +428,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -695,6 +775,93 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 	}
 }
 
+/*
+ * Print a progress report of worker threads. If verbose output
+ * is enabled, also print the current file name.
+ *
+ * Progress report is written at maximum once per second, unless the
+ * force parameter is set to true.
+ */
+static void
+workers_progress_report(uint64 totalBytesRead, const char *filename, bool force)
+{
+	int			percent;
+	char		totalBytesRead_str[32];
+	char		totalsize_str[32];
+	pg_time_t	now;
+
+	if (!showprogress)
+		return;
+
+	now = time(NULL);
+	if (now == last_progress_report && !force)
+		return;					/* Max once per second */
+
+	last_progress_report = now;
+	percent = totalsize_kb ? (int) ((totalBytesRead / 1024) * 100 / totalsize_kb) : 0;
+
+	/*
+	 * Avoid overflowing past 100% or the full size. This may make the total
+	 * size number change as we approach the end of the backup (the estimate
+	 * will always be wrong if WAL is included), but that's better than having
+	 * the done column be bigger than the total.
+	 */
+	if (percent > 100)
+		percent = 100;
+	if (totalBytesRead / 1024 > totalsize_kb)
+		totalsize_kb = totalBytesRead / 1024;
+
+	/*
+	 * Separate step to keep platform-dependent format code out of
+	 * translatable strings.  And we only test for INT64_FORMAT availability
+	 * in snprintf, not fprintf.
+	 */
+	snprintf(totalBytesRead_str, sizeof(totalBytesRead_str), INT64_FORMAT,
+			 totalBytesRead / 1024);
+	snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
+
+#define VERBOSE_FILENAME_LENGTH 35
+
+	if (verbose)
+	{
+		if (!filename)
+
+			/*
+			 * No filename given, so clear the status line (used for last
+			 * call)
+			 */
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied %*s"),
+					(int) strlen(totalsize_str),
+					totalBytesRead_str, totalsize_str,
+					percent,
+					VERBOSE_FILENAME_LENGTH + 5, "");
+		else
+		{
+			bool		truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied, current file (%s%-*.*s)"),
+					(int) strlen(totalsize_str), totalBytesRead_str, totalsize_str,
+					percent,
+					/* Prefix with "..." if we do leading truncation */
+							truncate ? "..." : "",
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+					/* Truncate filename at beginning if it's too long */
+							truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+				(int) strlen(totalsize_str),
+				totalBytesRead_str, totalsize_str,
+				percent);
+	}
+
+	if (isatty(fileno(stderr)))
+		fprintf(stderr, "\r");
+	else
+		fprintf(stderr, "\n");
+}
 
 /*
  * Print a progress report based on the global variables. If verbose output
@@ -711,7 +878,7 @@ progress_report(int tablespacenum, const char *filename, bool force)
 	char		totalsize_str[32];
 	pg_time_t	now;
 
-	if (!showprogress)
+	if (!showprogress || numWorkers > 1)
 		return;
 
 	now = time(NULL);
@@ -1381,7 +1548,7 @@ get_tablespace_mapping(const char *dir)
  * specified directory. If it's for another tablespace, it will be restored
  * in the original or mapped directory.
  */
-static void
+static int
 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 {
 	char		current_path[MAXPGPATH];
@@ -1392,6 +1559,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	bool		basetablespace;
 	char	   *copybuf = NULL;
 	FILE	   *file = NULL;
+	int			readBytes = 0;
 
 	basetablespace = PQgetisnull(res, rownum, 0);
 	if (basetablespace)
@@ -1455,7 +1623,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("invalid tar block header size: %d", r);
 				exit(1);
 			}
-			totaldone += 512;
+			readBytes += 512;
 
 			current_len_left = read_tar_number(&copybuf[124], 12);
 
@@ -1486,21 +1654,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * Directory
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
+
+					/*
+					 * In parallel mode, we create directories before fetching
+					 * files so its Ok if a directory already exist.
+					 */
 					if (mkdir(filename, pg_dir_create_mode) != 0)
 					{
-						/*
-						 * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
-						 * clusters) will have been created by the wal
-						 * receiver process. Also, when the WAL directory
-						 * location was specified, pg_wal (or pg_xlog) has
-						 * already been created as a symbolic link before
-						 * starting the actual backup. So just ignore creation
-						 * failures on related directories.
-						 */
-						if (!((pg_str_endswith(filename, "/pg_wal") ||
-							   pg_str_endswith(filename, "/pg_xlog") ||
-							   pg_str_endswith(filename, "/archive_status")) &&
-							  errno == EEXIST))
+						if (errno != EEXIST)
 						{
 							pg_log_error("could not create directory \"%s\": %m",
 										 filename);
@@ -1585,7 +1746,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				 */
 				fclose(file);
 				file = NULL;
-				totaldone += r;
+				readBytes += r;
 				continue;
 			}
 
@@ -1594,7 +1755,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("could not write to file \"%s\": %m", filename);
 				exit(1);
 			}
-			totaldone += r;
+			readBytes += r;
+			totaldone = readBytes;
 			progress_report(rownum, filename, false);
 
 			current_len_left -= r;
@@ -1622,13 +1784,11 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	if (copybuf != NULL)
 		PQfreemem(copybuf);
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
-
 	/*
 	 * No data is synced here, everything is done for all tablespaces at the
 	 * end.
 	 */
+	return readBytes;
 }
 
 
@@ -1715,16 +1875,29 @@ BaseBackup(void)
 			fprintf(stderr, "\n");
 	}
 
-	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
-				 escaped_label,
-				 showprogress ? "PROGRESS" : "",
-				 includewal == FETCH_WAL ? "WAL" : "",
-				 fastcheckpoint ? "FAST" : "",
-				 includewal == NO_WAL ? "" : "NOWAIT",
-				 maxrate_clause ? maxrate_clause : "",
-				 format == 't' ? "TABLESPACE_MAP" : "",
-				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	if (numWorkers <= 1)
+	{
+		basebkp =
+			psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 includewal == FETCH_WAL ? "WAL" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 includewal == NO_WAL ? "" : "NOWAIT",
+					 maxrate_clause ? maxrate_clause : "",
+					 format == 't' ? "TABLESPACE_MAP" : "",
+					 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	}
+	else
+	{
+		basebkp =
+			psprintf("START_BACKUP LABEL '%s' %s %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 maxrate_clause ? maxrate_clause : "",
+					 format == 't' ? "TABLESPACE_MAP" : "");
+	}
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
@@ -1774,7 +1947,7 @@ BaseBackup(void)
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1830,24 +2003,74 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		int j = 0,
+			k = 0;
 
-	if (showprogress)
+		backupInfo = palloc0(sizeof(BackupInfo));
+		backupInfo->workerConns = (PGconn **) palloc0(sizeof(PGconn *) * numWorkers);
+		backupInfo->tablespacecount = tablespacecount;
+		backupInfo->numWorkers = numWorkers;
+		strlcpy(backupInfo->xlogstart, xlogstart, sizeof(backupInfo->xlogstart));
+
+		read_label_tblspcmap(conn, &backupInfo->backup_label, &backupInfo->tablespace_map);
+
+		/* retrieve backup file list from the server. **/
+		GetBackupFileList(conn, backupInfo);
+
+		/*
+		 * add backup_label in backup, (for tar format, ReceiveTarFile() will
+		 * take care of it).
+		 */
+		if (format == 'p')
+			writefile("backup_label", backupInfo->backup_label);
+
+		/*
+		 * Flatten the file list to avoid unnecessary locks and enable the sequential
+		 * access to file list. (Creating an array of BackupFile structre pointers).
+		 */
+		backupInfo->files =
+			(BackupFile **) palloc0(sizeof(BackupFile *) * backupInfo->totalfiles);
+		for (i = 0; i < backupInfo->tablespacecount; i++)
+		{
+			TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+
+			for (j = 0; j < curTsInfo->numFiles; j++)
+			{
+				backupInfo->files[k] = &curTsInfo->backupFiles[j];
+				k++;
+			}
+		}
+
+		ParallelBackupRun(backupInfo);
+		StopBackup(backupInfo);
+	}
+	else
 	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+
+		if (showprogress)
+		{
+			progress_report(PQntuples(tablespacehdr), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
 	}
 
+	/* Write recovery contents */
+	if (format == 'p' && writerecoveryconf)
+		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
+
 	PQclear(res);
 
 	/*
@@ -2043,6 +2266,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2070,7 +2294,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2211,6 +2435,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2325,6 +2552,22 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (format != 'p' && numWorkers > 1)
+	{
+		pg_log_error("parallel jobs are only supported with 'plain' format");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2397,3 +2640,403 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+/*
+ * Thread worker
+ */
+static void *
+workerRun(void *arg)
+{
+	WorkerState *wstate = (WorkerState *) arg;
+
+	GetBackupFile(wstate);
+
+	wstate->terminated = true;
+	return NULL;
+}
+
+/*
+ * Runs the worker threads and updates progress until all workers have
+ * terminated/completed.
+ */
+static void
+ParallelBackupRun(BackupInfo *backupInfo)
+{
+	int		status,
+			i;
+	bool	threadsActive = true;
+	uint64	totalBytes = 0;
+
+	workers = (WorkerState *) palloc0(sizeof(WorkerState) * numWorkers);
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		WorkerState *worker = &workers[i];
+
+		worker->backupInfo = backupInfo;
+		worker->workerid = i;
+		worker->bytesRead = 0;
+		worker->terminated = false;
+
+		backupInfo->workerConns[i] = GetConnection();
+		status = pthread_create(&worker->worker, NULL, workerRun, worker);
+		if (status != 0)
+		{
+			pg_log_error("failed to create thread: %m");
+			exit(1);
+		}
+
+		if (verbose)
+			pg_log_info("backup worker (%d) created, %d", i, status);
+	}
+
+	/*
+	 * This is the main thread for updating progrsss. It waits for workers to
+	 * complete and gets updated status during every loop iteration.
+	 */
+	while(threadsActive)
+	{
+		char *filename = NULL;
+
+		threadsActive = false;
+		totalBytes = 0;
+
+		for (i = 0; i < numWorkers; i++)
+		{
+			WorkerState *worker = &workers[i];
+
+			totalBytes += worker->bytesRead;
+			threadsActive |= !worker->terminated;
+		}
+
+		if (backupInfo->fileIndex < backupInfo->totalfiles)
+			filename = backupInfo->files[backupInfo->fileIndex]->path;
+
+		workers_progress_report(totalBytes, filename, false);
+		pg_usleep(100000);
+	}
+
+	if (showprogress)
+	{
+		workers_progress_report(totalBytes, NULL, true);
+		if (isatty(fileno(stderr)))
+			fprintf(stderr, "\n");	/* Need to move to next line */
+	}
+}
+
+/*
+ * Take the system out of backup mode.
+ */
+static void
+StopBackup(BackupInfo *backupInfo)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP LABEL '%s' %s %s",
+					   backupInfo->backup_label,
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+	PQclear(res);
+}
+
+/*
+ * Retrive backup file list from the server and populate TablespaceInfo struct
+ * to keep track of tablespaces and its files.
+ */
+static void
+GetBackupFileList(PGconn *conn, BackupInfo *backupInfo)
+{
+	TablespaceInfo	*tsInfo;
+	PGresult   *res = NULL;
+	char	   *basebkp;
+	int			i;
+
+	backupInfo->tsInfo = palloc0(sizeof(TablespaceInfo) * backupInfo->tablespacecount);
+	tsInfo = backupInfo->tsInfo;
+
+	/*
+	 * Get list of files.
+	 */
+	basebkp = psprintf("SEND_BACKUP_FILELIST");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SEND_BACKUP_FILELIST", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * The list of files is grouped by tablespaces, and we want to fetch them
+	 * in the same order.
+	 */
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		bool		basetablespace;
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tsInfo[i].tblspcOid = atol(PQgetvalue(tablespacehdr, i, 0));
+		tsInfo[i].tablespace = PQgetvalue(tablespacehdr, i, 1);
+		tsInfo[i].numFiles = PQntuples(res);
+		tsInfo[i].backupFiles = palloc0(sizeof(BackupFile) * tsInfo[i].numFiles);
+
+		/* keep count of all files in backup */
+		backupInfo->totalfiles += tsInfo[i].numFiles;
+
+		for (int j = 0; j < tsInfo[i].numFiles; j++)
+		{
+			char	   *path = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+				create_backup_dirs(basetablespace, tsInfo[i].tablespace, path);
+
+			strlcpy(tsInfo[i].backupFiles[j].path, path, MAXPGPATH);
+			tsInfo[i].backupFiles[j].type = type;
+			tsInfo[i].backupFiles[j].size = size;
+			tsInfo[i].backupFiles[j].mtime = mtime;
+			tsInfo[i].backupFiles[j].tsIndex = i;
+		}
+
+		/* sort files in descending order, based on size */
+		qsort(tsInfo[i].backupFiles, tsInfo[i].numFiles,
+			  sizeof(BackupFile), &compareFileSize);
+		PQclear(res);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+}
+
+/*
+ * Retrive and write backup file from the server. The file list is provided by
+ * worker state. It pulls a single file from this list and writes it to the
+ * backup directory.
+ */
+static int
+GetBackupFile(WorkerState *wstate)
+{
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn = NULL;
+	BackupFile *fetchFile = NULL;
+	BackupInfo *backupInfo = NULL;
+
+	backupInfo = wstate->backupInfo;
+	worker_conn = backupInfo->workerConns[wstate->workerid];
+	while ((fetchFile = getNextFile(backupInfo)) != NULL)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+
+		/*
+		 * build query in form of: SEND_BACKUP_FILES ('base/1/1245/32683',
+		 * 'base/1/1245/32683', ...) [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_BACKUP_FILES ( '%s' )", fetchFile->path);
+
+		/* add options */
+		appendPQExpBuffer(buf, " START_WAL_LOCATION '%s' %s %s",
+						  backupInfo->xlogstart,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+
+		destroyPQExpBuffer(buf);
+
+		/* process file contents, also count bytesRead for progress */
+		wstate->bytesRead +=
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, fetchFile->tsIndex);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	return 0;
+}
+
+/*
+ * Increment fileIndex and store it in a local variable so that even a
+ * context switch does not affect the file index value and we don't accidentally
+ * increment the value twice and therefore skip some files.
+ */
+static BackupFile*
+getNextFile(BackupInfo *backupInfo)
+{
+	int fileIndex = 0;
+
+	pthread_mutex_lock(&fetch_mutex);
+	fileIndex = backupInfo->fileIndex++;
+	pthread_mutex_unlock(&fetch_mutex);
+
+	if (fileIndex >= backupInfo->totalfiles)
+		return NULL;
+
+	return backupInfo->files[fileIndex];
+}
+
+/* qsort comparator for BackupFile (sort descending order)  */
+static int
+compareFileSize(const void *a, const void *b)
+{
+	const		BackupFile *v1 = (BackupFile *) a;
+	const		BackupFile *v2 = (BackupFile *) b;
+
+	if (v1->size > v2->size)
+		return -1;
+	if (v1->size < v2->size)
+		return 1;
+
+	return 0;
+}
+
+static void
+read_label_tblspcmap(PGconn *conn, char **backuplabel, char **tblspc_map)
+{
+	PGresult   *res = NULL;
+
+	Assert(backuplabel != NULL);
+	Assert(tblspc_map != NULL);
+
+	/*
+	 * Get Backup label and tablespace map data.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) < 1)
+	{
+		pg_log_error("no data returned from server");
+		exit(1);
+	}
+
+	*backuplabel = PQgetvalue(res, 0, 0);	/* backup_label */
+	if (!PQgetisnull(res, 0, 1))
+		*tblspc_map = PQgetvalue(res, 0, 1);	/* tablespace_map */
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	PQclear(res);
+}
+
+/*
+ * Create backup direcotries while taking care of tablespace path. If tablespace
+ * mapping (with -T) is given then the directory will be created on the mapped
+ * path.
+ */
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char	dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+/*
+ * General function for writing to a file; creates one if it doesn't exist
+ */
+static void
+writefile(char *path, char *buf)
+{
+	FILE   *f;
+	char	pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
-- 
2.21.0 (Apple Git-122.2)

0001-remove-PG_ENSURE_ERROR_CLEANUP-macro-from-basebackup.patchapplication/octet-stream; name=0001-remove-PG_ENSURE_ERROR_CLEANUP-macro-from-basebackup.patchDownload
From 15979957334de59b21082ce1029cad240e937d99 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 10:21:38 +0500
Subject: [PATCH 1/7] remove PG_ENSURE_ERROR_CLEANUP macro from basebackup.
 register base_backup_cleanup with before_shmem_exit handler. This will make
 sure that call is always made when wal sender exits.

---
 src/backend/replication/basebackup.c | 182 +++++++++++++--------------
 1 file changed, 90 insertions(+), 92 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 1fa4551eff..71a8b4fb4c 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -243,6 +243,8 @@ perform_base_backup(basebackup_options *opt)
 	StringInfo	tblspc_map_file = NULL;
 	int			datadirpathlen;
 	List	   *tablespaces = NIL;
+	ListCell   *lc;
+	tablespaceinfo *ti;
 
 	datadirpathlen = strlen(DataDir);
 
@@ -261,121 +263,117 @@ perform_base_backup(basebackup_options *opt)
 	/*
 	 * Once do_pg_start_backup has been called, ensure that any failure causes
 	 * us to abort the backup so we don't "leak" a backup counter. For this
-	 * reason, *all* functionality between do_pg_start_backup() and the end of
-	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 * reason, register base_backup_cleanup with before_shmem_exit handler. This
+	 * will make sure that call is always made when process exits. In success,
+	 * do_pg_stop_backup will have taken the system out of backup mode and this
+	 * callback will have no effect, Otherwise the required cleanup will be done
+	 * in any case.
 	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
 
-	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
-	{
-		ListCell   *lc;
-		tablespaceinfo *ti;
-
-		SendXlogRecPtrResult(startptr, starttli);
+	SendXlogRecPtrResult(startptr, starttli);
 
-		/*
-		 * Calculate the relative path of temporary statistics directory in
-		 * order to skip the files which are located in that directory later.
-		 */
-		if (is_absolute_path(pgstat_stat_directory) &&
-			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
-		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory);
-		else
-			statrelpath = pgstat_stat_directory;
-
-		/* Add a node for the base directory at the end */
-		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
-		tablespaces = lappend(tablespaces, ti);
+	/*
+	 * Calculate the relative path of temporary statistics directory in
+	 * order to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
 
-		/* Send tablespace header */
-		SendBackupHeader(tablespaces);
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	tablespaces = lappend(tablespaces, ti);
 
-		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
 
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
+	/* Setup and activate network throttling, if client requested it */
+	if (opt->maxrate > 0)
+	{
+		throttling_sample =
+			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
 
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
 
-		/* Send off our tablespaces one by one */
-		foreach(lc, tablespaces)
-		{
-			tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
-			StringInfoData buf;
+		/* Enable throttling. */
+		throttling_counter = 0;
 
-			/* Send CopyOutResponse message */
-			pq_beginmessage(&buf, 'H');
-			pq_sendbyte(&buf, 0);	/* overall format */
-			pq_sendint16(&buf, 0);	/* natts */
-			pq_endmessage(&buf);
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
 
-			if (ti->path == NULL)
-			{
-				struct stat statbuf;
+	/* Send off our tablespaces one by one */
+	foreach(lc, tablespaces)
+	{
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+		StringInfoData buf;
 
-				/* In the main tar, include the backup_label first... */
-				sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
+		/* Send CopyOutResponse message */
+		pq_beginmessage(&buf, 'H');
+		pq_sendbyte(&buf, 0);	/* overall format */
+		pq_sendint16(&buf, 0);	/* natts */
+		pq_endmessage(&buf);
 
-				/*
-				 * Send tablespace_map file if required and then the bulk of
-				 * the files.
-				 */
-				if (tblspc_map_file && opt->sendtblspcmapfile)
-				{
-					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-					sendDir(".", 1, false, tablespaces, false);
-				}
-				else
-					sendDir(".", 1, false, tablespaces, true);
+		if (ti->path == NULL)
+		{
+			struct stat statbuf;
 
-				/* ... and pg_control after everything else. */
-				if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
-					ereport(ERROR,
-							(errcode_for_file_access(),
-							 errmsg("could not stat file \"%s\": %m",
-									XLOG_CONTROL_FILE)));
-				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
-			}
-			else
-				sendTablespace(ti->path, false);
+			/* In the main tar, include the backup_label first... */
+			sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
 
 			/*
-			 * If we're including WAL, and this is the main data directory we
-			 * don't terminate the tar stream here. Instead, we will append
-			 * the xlog files below and terminate it then. This is safe since
-			 * the main data directory is always sent *last*.
+			 * Send tablespace_map file if required and then the bulk of
+			 * the files.
 			 */
-			if (opt->includewal && ti->path == NULL)
+			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
-				Assert(lnext(tablespaces, lc) == NULL);
+				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
+				sendDir(".", 1, false, tablespaces, false);
 			}
 			else
-				pq_putemptymessage('c');	/* CopyDone */
+				sendDir(".", 1, false, tablespaces, true);
+
+			/* ... and pg_control after everything else. */
+			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file \"%s\": %m",
+								XLOG_CONTROL_FILE)));
+			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
+		else
+			sendTablespace(ti->path, false);
 
-		endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+		/*
+		 * If we're including WAL, and this is the main data directory we
+		 * don't terminate the tar stream here. Instead, we will append
+		 * the xlog files below and terminate it then. This is safe since
+		 * the main data directory is always sent *last*.
+		 */
+		if (opt->includewal && ti->path == NULL)
+		{
+			Assert(lnext(tablespaces, lc) == NULL);
+		}
+		else
+			pq_putemptymessage('c');	/* CopyDone */
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 
+	endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
 
 	if (opt->includewal)
 	{
-- 
2.21.0 (Apple Git-122.2)

0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchapplication/octet-stream; name=0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchDownload
From f24c0bfcae411b38d689523d0329d830d9aa191f Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 16:45:28 +0500
Subject: [PATCH 2/7] Rename sizeonly to dryrun for few functions in
 basebackup.

---
 src/backend/replication/basebackup.c | 44 ++++++++++++++--------------
 src/include/replication/basebackup.h |  2 +-
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 71a8b4fb4c..267163ed29 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -54,15 +54,15 @@ typedef struct
 } basebackup_options;
 
 
-static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
+static int64 sendDir(const char *path, int basepathlen, bool dryrun,
 					 List *tablespaces, bool sendtblspclinks);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
 static int64 _tarWriteHeader(const char *filename, const char *linktarget,
-							 struct stat *statbuf, bool sizeonly);
+							 struct stat *statbuf, bool dryrun);
 static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-						  bool sizeonly);
+						  bool dryrun);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
@@ -959,13 +959,13 @@ sendFileWithContent(const char *filename, const char *content)
 
 /*
  * Include the tablespace directory pointed to by 'path' in the output tar
- * stream.  If 'sizeonly' is true, we just calculate a total length and return
+ * stream.  If 'dryrun' is true, we just calculate a total length and return
  * it, without actually sending anything.
  *
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool dryrun)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -995,17 +995,17 @@ sendTablespace(char *path, bool sizeonly)
 	}
 
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
-						   sizeonly);
+						   dryrun);
 
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
 
 	return size;
 }
 
 /*
  * Include all files from the given directory in the output tar stream. If
- * 'sizeonly' is true, we just calculate a total length and return it, without
+ * 'dryrun' is true, we just calculate a total length and return it, without
  * actually sending anything.
  *
  * Omit any directory in the tablespaces list, to avoid backing up
@@ -1016,7 +1016,7 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		bool sendtblspclinks)
 {
 	DIR		   *dir;
@@ -1171,7 +1171,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
-				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
 			}
@@ -1187,7 +1187,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
 
@@ -1199,14 +1199,14 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (strcmp(pathbuf, "./pg_wal") == 0)
 		{
 			/* If pg_wal is a symlink, write it as a directory anyway */
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 
 			/*
 			 * Also send archive_status directory (by hackishly reusing
 			 * statbuf from above ...).
 			 */
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			continue;			/* don't recurse into pg_wal */
 		}
@@ -1238,7 +1238,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			linkpath[rllen] = '\0';
 
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
-									&statbuf, sizeonly);
+									&statbuf, dryrun);
 #else
 
 			/*
@@ -1262,7 +1262,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 * permissions right.
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1293,17 +1293,17 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			if (!dryrun)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
-			if (sent || sizeonly)
+			if (sent || dryrun)
 			{
 				/* Add size, rounded up to 512byte block */
 				size += ((statbuf.st_size + 511) & ~511);
@@ -1612,12 +1612,12 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
 
 static int64
 _tarWriteHeader(const char *filename, const char *linktarget,
-				struct stat *statbuf, bool sizeonly)
+				struct stat *statbuf, bool dryrun)
 {
 	char		h[512];
 	enum tarError rc;
 
-	if (!sizeonly)
+	if (!dryrun)
 	{
 		rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
 							 statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
@@ -1654,7 +1654,7 @@ _tarWriteHeader(const char *filename, const char *linktarget,
  */
 static int64
 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-			 bool sizeonly)
+			 bool dryrun)
 {
 	/* If symlink, write it as a directory anyway */
 #ifndef WIN32
@@ -1664,7 +1664,7 @@ _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
 #endif
 		statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
 
-	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
+	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, dryrun);
 }
 
 /*
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..b55917b9b6 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool dryrun);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122.2)

0003-Refactor-some-basebackup-code-to-increase-reusabilit.patchapplication/octet-stream; name=0003-Refactor-some-basebackup-code-to-increase-reusabilit.patchDownload
From 0d9d46b8c0a21eec50a5ee4f2855e17f453ae03a Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 9 Oct 2019 12:39:41 +0500
Subject: [PATCH 3/7] Refactor some basebackup code to increase reusability, in
 anticipation of adding parallel backup

---
 src/backend/access/transam/xlog.c    | 192 +++++-----
 src/backend/replication/basebackup.c | 512 ++++++++++++++-------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 371 insertions(+), 335 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 3b766e66b9..451fe6c0d1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10300,10 +10300,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10429,93 +10425,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collectTablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12291,3 +12201,103 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+				   bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to
+		 * ensure that we can distinguish between the newline in the
+		 * tablespace path and end of line while reading tablespace_map
+		 * file during archive recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory
+		 * when it's located within PGDATA, or NULL if it's located
+		 * elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created
+		 * them. Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 267163ed29..b679f36021 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -67,10 +67,12 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt);
+static void include_wal_files(XLogRecPtr endptr);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
+static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
@@ -293,29 +295,7 @@ perform_base_backup(basebackup_options *opt)
 	/* Send tablespace header */
 	SendBackupHeader(tablespaces);
 
-	/* Setup and activate network throttling, if client requested it */
-	if (opt->maxrate > 0)
-	{
-		throttling_sample =
-			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-		/*
-		 * The minimum amount of time for throttling_sample bytes to be
-		 * transferred.
-		 */
-		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-		/* Enable throttling. */
-		throttling_counter = 0;
-
-		/* The 'real data' starts now (header was ignored). */
-		throttled_last = GetCurrentTimestamp();
-	}
-	else
-	{
-		/* Disable throttling. */
-		throttling_counter = -1;
-	}
+	setup_throttle(opt->maxrate);
 
 	/* Send off our tablespaces one by one */
 	foreach(lc, tablespaces)
@@ -381,227 +361,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -1740,3 +1500,267 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * Append the required WAL files to the backup tar file. It assumes that the
+ * last tar file is "open" and the WALs will be appended to it.
+ */
+static void
+include_wal_files(XLogRecPtr endptr)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the
+	 * required WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and
+	 * include all WAL files in the range between 'startptr' and 'endptr',
+	 * regardless of the timeline the file is stamped with. If there are
+	 * some spurious WAL files belonging to timelines that don't belong in
+	 * this server's history, they will be included too. Normally there
+	 * shouldn't be such files, but if there are, there's little harm in
+	 * including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we
+	 * need were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from
+	 * oldest to newest, to reduce the chance that a file is recycled
+	 * before we get a chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since
+	 * we are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		CHECK_FREAD_ERROR(fp, pathbuf);
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again
+		 * after promotion of a new node. This is in line with
+		 * walreceiver.c always doing an XLogArchiveForceDone() after a
+		 * complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history
+	 * file is required for recovery, and even that only if there happens
+	 * to be a timeline switch in the first WAL segment that contains the
+	 * checkpoint record, or if we're taking a base backup from a standby
+	 * server and the target timeline changes while the backup is taken.
+	 * But they are small and highly useful for debugging purposes, so
+	 * better include them all, always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d519252aad..5b0aa8ae85 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 									 bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
+extern void collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+							   bool infotbssize, bool needtblspcmapfile);
 extern void do_pg_abort_backup(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.0 (Apple Git-122.2)

0006-parallel-backup-testcase.patchapplication/octet-stream; name=0006-parallel-backup-testcase.patchDownload
From 0fe5f785e1c426abf660215279ae28ff5b6e156a Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 6/7] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 527 ++++++++++++++++++
 1 file changed, 527 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..4ec4c1e0f6
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,527 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 95;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+#	# Create a temporary directory in the system location and symlink it
+#	# to our physical temp location.  That way we can use shorter names
+#	# for the tablespace directories, which hopefully won't run afoul of
+#	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+my $file;
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.0 (Apple Git-122.2)

0007-parallel-backup-documentation.patchapplication/octet-stream; name=0007-parallel-backup-documentation.patchDownload
From fa4fe2ed932ddef90ff2e4cff1e42715139f8d4c Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Thu, 7 Nov 2019 16:52:40 +0500
Subject: [PATCH 7/7] parallel backup documentation

---
 doc/src/sgml/protocol.sgml          | 386 ++++++++++++++++++++++++++++
 doc/src/sgml/ref/pg_basebackup.sgml |  20 ++
 2 files changed, 406 insertions(+)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 80275215e0..22d620c346 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2700,6 +2700,392 @@ The commands accepted in replication mode are:
      </para>
     </listitem>
   </varlistentry>
+  
+  <varlistentry>
+    <term><literal>START_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>PROGRESS</literal> ]
+        [ <literal>FAST</literal> ]
+        [ <literal>TABLESPACE_MAP</literal> ]
+
+     <indexterm><primary>START_BACKUP</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to prepare for performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><literal>LABEL</literal> <replaceable>'label'</replaceable></term>
+        <listitem>
+         <para>
+          Sets the label of the backup. If none is specified, a backup label
+          of <literal>start backup</literal> will be used. The quoting rules
+          for the label are the same as a standard SQL string with
+          <xref linkend="guc-standard-conforming-strings"/> turned on.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>PROGRESS</literal></term>
+        <listitem>
+         <para>
+          Request information required to generate a progress report. This will
+          send back an approximate size in the header of each tablespace, which
+          can be used to calculate how far along the stream is done. This is
+          calculated by enumerating all the file sizes once before the transfer
+          is even started, and might as such have a negative impact on the
+          performance.  In particular, it might take longer before the first data
+          is streamed. Since the database files can change during the backup,
+          the size is only approximate and might both grow and shrink between
+          the time of approximation and the sending of the actual files.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>FAST</literal></term>
+        <listitem>
+         <para>
+          Request a fast checkpoint.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>TABLESPACE_MAP</literal></term>
+        <listitem>
+         <para>
+          Include information about symbolic links present in the directory
+          <filename>pg_tblspc</filename> in a file named
+          <filename>tablespace_map</filename>. The tablespace map file includes
+          each symbolic link name as it exists in the directory
+          <filename>pg_tblspc/</filename> and the full path of that symbolic link.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     
+     <para>
+      In response to this command, server will send out three result sets.
+     </para>
+     <para>
+      The first ordinary result set contains the starting position of the
+      backup, in a single row with two columns. The first column contains
+      the start position given in XLogRecPtr format, and the second column
+      contains the corresponding timeline ID.
+     </para>
+     
+     <para>
+      The second ordinary result set has one row for each tablespace.
+      The fields in this row are:
+      <variablelist>
+       <varlistentry>
+        <term><literal>spcoid</literal> (<type>oid</type>)</term>
+        <listitem>
+         <para>
+          The OID of the tablespace, or null if it's the base
+          directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>spclocation</literal> (<type>text</type>)</term>
+        <listitem>
+         <para>
+          The full path of the tablespace directory, or null
+          if it's the base directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the tablespace, in kilobytes (1024 bytes),
+          if progress report has been requested; otherwise it's null.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+     <para>
+      The final result set will be sent in a single row with two columns. The
+      first column contains the data of <filename>backup_label</filename> file,
+      and the second column contains the data of <filename>tablespace_map</filename>.
+     </para>
+
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>STOP_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>WAL</literal> ]
+        [ <literal>NOWAIT</literal> ]
+
+     <indexterm><primary>STOP_BACKUP</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to finish performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><replaceable class="parameter">LABEL</replaceable><replaceable>'string'</replaceable></term>
+        <listitem>
+         <para>
+          Provides the content of backup_label file to the backup. The content are
+          the same that were returned by <command>START_BACKUP</command>.
+         </para>
+        </listitem>
+       </varlistentry>
+        <varlistentry>
+        <term><literal>WAL</literal></term>
+        <listitem>
+         <para>
+          Include the necessary WAL segments in the backup. This will include
+          all the files between start and stop backup in the
+          <filename>pg_wal</filename> directory of the base directory tar
+          file.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>NOWAIT</literal></term>
+        <listitem>
+         <para>
+          By default, the backup will wait until the last required WAL
+          segment has been archived, or emit a warning if log archiving is
+          not enabled. Specifying <literal>NOWAIT</literal> disables both
+          the waiting and the warning, leaving the client responsible for
+          ensuring the required log is available.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+     <para>
+      In response to this command, server will send one or more CopyResponse
+      results followed by a single result set, containing the WAL end position of
+      the backup. The CopyResponse contains <filename>pg_control</filename> and
+      WAL files, if stop backup is run with WAL option.
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_BACKUP_FILELIST</literal>
+        <indexterm><primary>SEND_BACKUP_FILELIST</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instruct the server to return a list of files and directories, available in
+      data directory. In response to this command, server will send one result set
+      per tablespace. The result sets consist of following fields:
+     </para>
+
+     <variablelist>
+      <varlistentry>
+       <term><literal>path</literal> (<type>text</type>)</term>
+       <listitem>
+        <para>
+         The path and name of the file. In case of tablespace, it is an absolute
+         path on the database server, however, in case of <filename>base</filename>
+         tablespace, it is relative to $PGDATA.
+        </para>
+       </listitem>
+      </varlistentry>
+    
+      <varlistentry>
+       <term><literal>type</literal> (<type>char</type>)</term>
+       <listitem>
+        <para>
+         A single character, identifing the type of file.
+         <itemizedlist spacing="compact" mark="bullet">
+          <listitem>
+           <para>
+            <literal>'f'</literal> - Regular file. Can be any relation or
+            non-relation file in $PGDATA.
+           </para>
+          </listitem>
+    
+          <listitem>
+           <para>
+            <literal>'d'</literal> - Directory.
+           </para>
+          </listitem>
+    
+          <listitem>
+           <para>
+            <literal>'l'</literal> - Symbolic link.
+           </para>
+          </listitem>
+         </itemizedlist>
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the file, in kilobytes (1024 bytes). It's null if
+          type is 'd' or 'l'.
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>mtime</literal> (<type>Int64</type>)</term>
+        <listitem>
+         <para>
+          The file or directory last modification time, as seconds since the Epoch.
+         </para>
+        </listitem>
+      </varlistentry>
+     </variablelist>
+
+      <para>
+       This list will contain all files and directories in the $PGDATA, regardless of
+       whether they are PostgreSQL files or other files added to the same directory.
+       The only excluded files are:
+       <itemizedlist spacing="compact" mark="bullet">
+        <listitem>
+         <para>
+          <filename>postmaster.pid</filename>
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>postmaster.opts</filename>
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_internal.init</filename> (found in multiple directories)
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Various temporary files and directories created during the operation
+          of the PostgreSQL server, such as any file or directory beginning
+          with <filename>pgsql_tmp</filename> and temporary relations.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Unlogged relations, except for the init fork which is required to
+          recreate the (empty) unlogged relation on recovery.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_wal</filename>, including subdirectories. If the backup is run
+          with WAL files included, a synthesized version of <filename>pg_wal</filename> will be
+          included, but it will only contain the files necessary for the
+          backup to work, not the rest of the contents.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_dynshmem</filename>, <filename>pg_notify</filename>,
+          <filename>pg_replslot</filename>, <filename>pg_serial</filename>,
+          <filename>pg_snapshots</filename>, <filename>pg_stat_tmp</filename>, and
+          <filename>pg_subtrans</filename> are copied as empty directories (even if
+          they are symbolic links).
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Files other than regular files and directories, such as symbolic
+          links (other than for the directories listed above) and special
+          device files, are skipped.  (Symbolic links
+          in <filename>pg_tblspc</filename> are maintained.)
+         </para>
+        </listitem>
+       </itemizedlist>
+       Owner, group, and file mode are set if the underlying file system on the server
+       supports it.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_BACKUP_FILES ( <replaceable class="parameter">'FILE'</replaceable> [, ...] )</literal>
+        [ <literal>MAX_RATE</literal> <replaceable>rate</replaceable> ]
+        [ <literal>NOVERIFY_CHECKSUMS</literal> ]
+        [ <literal>START_WAL_LOCATION</literal> ]
+
+        <indexterm><primary>SEND_BACKUP_FILES</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to send the contents of the requested FILE(s).
+     </para>
+      
+     <para>
+      A clause of the form <literal>SEND_BACKUP_FILES ( 'FILE', 'FILE', ... ) [OPTIONS]</literal>
+      is accepted where one or more FILE(s) can be requested.
+     </para>
+
+     <para>
+      In response to this command, one or more CopyResponse results will be sent,
+      one for each FILE requested. The data in the CopyResponse results will be
+      a tar format (following the “ustar interchange format” specified in the
+      POSIX 1003.1-2008 standard) dump of the tablespace contents, except that
+      the two trailing blocks of zeroes specified in the standard are omitted.
+     </para>
+
+     <para>
+      The following options are accepted:
+       <variablelist>
+        <varlistentry>
+         <term><literal>MAX_RATE</literal> <replaceable>rate</replaceable></term>
+         <listitem>
+          <para>
+           Limit (throttle) the maximum amount of data transferred from server
+           to client per unit of time. The expected unit is kilobytes per second.
+           If this option is specified, the value must either be equal to zero
+           or it must fall within the range from 32 kB through 1 GB (inclusive).
+           If zero is passed or the option is not specified, no restriction is
+           imposed on the transfer.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>NOVERIFY_CHECKSUMS</literal></term>
+         <listitem>
+          <para>
+           By default, checksums are verified during a base backup if they are
+           enabled. Specifying <literal>NOVERIFY_CHECKSUMS</literal> disables
+           this verification.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>START_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The starting WAL position when START BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+        </varlistentry>
+       </variablelist>
+     </para>
+    </listitem>
+  </varlistentry>
 </variablelist>
 
 </para>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index fc9e222f8d..339e68bda7 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -536,6 +536,26 @@ PostgreSQL documentation
        </para>
       </listitem>
      </varlistentry>
+     
+     <varlistentry>
+      <term><option>-j <replaceable class="parameter">n</replaceable></option></term>
+      <term><option>--jobs=<replaceable class="parameter">n</replaceable></option></term>
+      <listitem>
+       <para>
+        Create <replaceable class="parameter">n</replaceable> threads to copy
+        backup files from the database server. <application>pg_basebackup</application>
+        will open <replaceable class="parameter">n</replaceable> +1 connections
+        to the database. Therefore, the server must be configured with
+        <xref linkend="guc-max-wal-senders"/> set high enough to accommodate all
+        connections.
+       </para>
+       
+       <para>
+        parallel mode only works with plain format.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </para>
 
-- 
2.21.0 (Apple Git-122.2)

#34Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#33)
7 attachment(s)
Re: WIP/PoC for parallel backup

On Tue, Nov 12, 2019 at 5:07 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Mon, Nov 4, 2019 at 6:08 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Fri, Nov 1, 2019 at 8:53 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Oct 30, 2019 at 10:16 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

'startptr' is used by sendFile() during checksum verification. Since
SendBackupFiles() is using sendFIle we have to set a valid WAL

location.

Ugh, global variables.

Why are START_BACKUP, SEND_BACKUP_FILELIST, SEND_BACKUP_FILES, and
STOP_BACKUP all using the same base_backup_opt_list production as
BASE_BACKUP? Presumably most of those options are not applicable to
most of those commands, and the productions should therefore be
separated.

Are you expecting something like the attached patch? Basically I have
reorganised the grammar
rules so each command can have the options required by it.

I was feeling a bit reluctant for this change because it may add some
unwanted grammar rules in
the replication grammar. Since these commands are using the same options
as base backup, may
be we could throw error inside the relevant functions on unwanted options?

You should add docs, too. I wouldn't have to guess what some of this
stuff was for if you wrote documentation explaining what this stuff
was for. :-)

Yes I will add it in the next patch.

The tablespace_path option appears entirely unused, and I don't know
why that should be necessary here, either.

This is to calculate the basepathlen. We need to exclude the

tablespace location (or

base path) from the filename before it is sent to the client with

sendFile call. I added

this option primarily to avoid performing string manipulation on

filename to extract the

tablespace location and then calculate the basepathlen.

Alternatively we can do it by extracting the base path from the

received filename. What

do you suggest?

I don't think the server needs any information from the client in
order to be able to exclude the tablespace location from the pathname.
Whatever it needs to know, it should be able to figure out, just as it
would in a non-parallel backup.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

I have updated the replication grammar with some new rules to
differentiate the options production
for base backup and newly added commands.

I have also created a separate patch to include the documentation changes.
The current syntax is as below:

- START_BACKUP [ LABEL 'label' ] [ PROGRESS ] [ FAST ] [ TABLESPACE_MAP ]
- STOP_BACKUP [ LABEL 'label' ] [ WAL ] [ NOWAIT ]
- SEND_BACKUP_FILELIST
- SEND_BACKUP_FILES ( 'FILE' [, ...] ) [ MAX_RATE rate ] [
NOVERIFY_CHECKSUMS ] [ START_WAL_LOCATION ]

Sorry, I sent the wrong patches. Please see the correct version of the
patches (_v6).

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0001-remove-PG_ENSURE_ERROR_CLEANUP-macro-from-basebackup_v6.patchapplication/octet-stream; name=0001-remove-PG_ENSURE_ERROR_CLEANUP-macro-from-basebackup_v6.patchDownload
From 97d7f929ffd5832437c332976c9252b2d9fefe5b Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 10:21:38 +0500
Subject: [PATCH 1/7] remove PG_ENSURE_ERROR_CLEANUP macro from basebackup.
 register base_backup_cleanup with before_shmem_exit handler. This will make
 sure that call is always made when wal sender exits.

---
 src/backend/replication/basebackup.c | 182 +++++++++++++--------------
 1 file changed, 90 insertions(+), 92 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 1fa4551eff..71a8b4fb4c 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -243,6 +243,8 @@ perform_base_backup(basebackup_options *opt)
 	StringInfo	tblspc_map_file = NULL;
 	int			datadirpathlen;
 	List	   *tablespaces = NIL;
+	ListCell   *lc;
+	tablespaceinfo *ti;
 
 	datadirpathlen = strlen(DataDir);
 
@@ -261,121 +263,117 @@ perform_base_backup(basebackup_options *opt)
 	/*
 	 * Once do_pg_start_backup has been called, ensure that any failure causes
 	 * us to abort the backup so we don't "leak" a backup counter. For this
-	 * reason, *all* functionality between do_pg_start_backup() and the end of
-	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 * reason, register base_backup_cleanup with before_shmem_exit handler. This
+	 * will make sure that call is always made when process exits. In success,
+	 * do_pg_stop_backup will have taken the system out of backup mode and this
+	 * callback will have no effect, Otherwise the required cleanup will be done
+	 * in any case.
 	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
 
-	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
-	{
-		ListCell   *lc;
-		tablespaceinfo *ti;
-
-		SendXlogRecPtrResult(startptr, starttli);
+	SendXlogRecPtrResult(startptr, starttli);
 
-		/*
-		 * Calculate the relative path of temporary statistics directory in
-		 * order to skip the files which are located in that directory later.
-		 */
-		if (is_absolute_path(pgstat_stat_directory) &&
-			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
-		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory);
-		else
-			statrelpath = pgstat_stat_directory;
-
-		/* Add a node for the base directory at the end */
-		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
-		tablespaces = lappend(tablespaces, ti);
+	/*
+	 * Calculate the relative path of temporary statistics directory in
+	 * order to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
 
-		/* Send tablespace header */
-		SendBackupHeader(tablespaces);
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	tablespaces = lappend(tablespaces, ti);
 
-		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
 
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
+	/* Setup and activate network throttling, if client requested it */
+	if (opt->maxrate > 0)
+	{
+		throttling_sample =
+			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
 
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
 
-		/* Send off our tablespaces one by one */
-		foreach(lc, tablespaces)
-		{
-			tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
-			StringInfoData buf;
+		/* Enable throttling. */
+		throttling_counter = 0;
 
-			/* Send CopyOutResponse message */
-			pq_beginmessage(&buf, 'H');
-			pq_sendbyte(&buf, 0);	/* overall format */
-			pq_sendint16(&buf, 0);	/* natts */
-			pq_endmessage(&buf);
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
 
-			if (ti->path == NULL)
-			{
-				struct stat statbuf;
+	/* Send off our tablespaces one by one */
+	foreach(lc, tablespaces)
+	{
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+		StringInfoData buf;
 
-				/* In the main tar, include the backup_label first... */
-				sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
+		/* Send CopyOutResponse message */
+		pq_beginmessage(&buf, 'H');
+		pq_sendbyte(&buf, 0);	/* overall format */
+		pq_sendint16(&buf, 0);	/* natts */
+		pq_endmessage(&buf);
 
-				/*
-				 * Send tablespace_map file if required and then the bulk of
-				 * the files.
-				 */
-				if (tblspc_map_file && opt->sendtblspcmapfile)
-				{
-					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-					sendDir(".", 1, false, tablespaces, false);
-				}
-				else
-					sendDir(".", 1, false, tablespaces, true);
+		if (ti->path == NULL)
+		{
+			struct stat statbuf;
 
-				/* ... and pg_control after everything else. */
-				if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
-					ereport(ERROR,
-							(errcode_for_file_access(),
-							 errmsg("could not stat file \"%s\": %m",
-									XLOG_CONTROL_FILE)));
-				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
-			}
-			else
-				sendTablespace(ti->path, false);
+			/* In the main tar, include the backup_label first... */
+			sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
 
 			/*
-			 * If we're including WAL, and this is the main data directory we
-			 * don't terminate the tar stream here. Instead, we will append
-			 * the xlog files below and terminate it then. This is safe since
-			 * the main data directory is always sent *last*.
+			 * Send tablespace_map file if required and then the bulk of
+			 * the files.
 			 */
-			if (opt->includewal && ti->path == NULL)
+			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
-				Assert(lnext(tablespaces, lc) == NULL);
+				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
+				sendDir(".", 1, false, tablespaces, false);
 			}
 			else
-				pq_putemptymessage('c');	/* CopyDone */
+				sendDir(".", 1, false, tablespaces, true);
+
+			/* ... and pg_control after everything else. */
+			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file \"%s\": %m",
+								XLOG_CONTROL_FILE)));
+			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
+		else
+			sendTablespace(ti->path, false);
 
-		endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+		/*
+		 * If we're including WAL, and this is the main data directory we
+		 * don't terminate the tar stream here. Instead, we will append
+		 * the xlog files below and terminate it then. This is safe since
+		 * the main data directory is always sent *last*.
+		 */
+		if (opt->includewal && ti->path == NULL)
+		{
+			Assert(lnext(tablespaces, lc) == NULL);
+		}
+		else
+			pq_putemptymessage('c');	/* CopyDone */
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 
+	endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
 
 	if (opt->includewal)
 	{
-- 
2.21.0 (Apple Git-122.2)

0003-Refactor-some-basebackup-code-to-increase-reusabilit_v6.patchapplication/octet-stream; name=0003-Refactor-some-basebackup-code-to-increase-reusabilit_v6.patchDownload
From b7d3df86224b4b3b10014d2b4a9d0d7a873f0772 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 9 Oct 2019 12:39:41 +0500
Subject: [PATCH 3/7] Refactor some basebackup code to increase reusability, in
 anticipation of adding parallel backup

---
 src/backend/access/transam/xlog.c    | 192 +++++-----
 src/backend/replication/basebackup.c | 512 ++++++++++++++-------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 371 insertions(+), 335 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 3b766e66b9..451fe6c0d1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10300,10 +10300,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10429,93 +10425,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collectTablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12291,3 +12201,103 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+				   bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to
+		 * ensure that we can distinguish between the newline in the
+		 * tablespace path and end of line while reading tablespace_map
+		 * file during archive recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory
+		 * when it's located within PGDATA, or NULL if it's located
+		 * elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created
+		 * them. Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 267163ed29..b679f36021 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -67,10 +67,12 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt);
+static void include_wal_files(XLogRecPtr endptr);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
+static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
@@ -293,29 +295,7 @@ perform_base_backup(basebackup_options *opt)
 	/* Send tablespace header */
 	SendBackupHeader(tablespaces);
 
-	/* Setup and activate network throttling, if client requested it */
-	if (opt->maxrate > 0)
-	{
-		throttling_sample =
-			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-		/*
-		 * The minimum amount of time for throttling_sample bytes to be
-		 * transferred.
-		 */
-		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-		/* Enable throttling. */
-		throttling_counter = 0;
-
-		/* The 'real data' starts now (header was ignored). */
-		throttled_last = GetCurrentTimestamp();
-	}
-	else
-	{
-		/* Disable throttling. */
-		throttling_counter = -1;
-	}
+	setup_throttle(opt->maxrate);
 
 	/* Send off our tablespaces one by one */
 	foreach(lc, tablespaces)
@@ -381,227 +361,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -1740,3 +1500,267 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * Append the required WAL files to the backup tar file. It assumes that the
+ * last tar file is "open" and the WALs will be appended to it.
+ */
+static void
+include_wal_files(XLogRecPtr endptr)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the
+	 * required WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and
+	 * include all WAL files in the range between 'startptr' and 'endptr',
+	 * regardless of the timeline the file is stamped with. If there are
+	 * some spurious WAL files belonging to timelines that don't belong in
+	 * this server's history, they will be included too. Normally there
+	 * shouldn't be such files, but if there are, there's little harm in
+	 * including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we
+	 * need were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from
+	 * oldest to newest, to reduce the chance that a file is recycled
+	 * before we get a chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since
+	 * we are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		CHECK_FREAD_ERROR(fp, pathbuf);
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again
+		 * after promotion of a new node. This is in line with
+		 * walreceiver.c always doing an XLogArchiveForceDone() after a
+		 * complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history
+	 * file is required for recovery, and even that only if there happens
+	 * to be a timeline switch in the first WAL segment that contains the
+	 * checkpoint record, or if we're taking a base backup from a standby
+	 * server and the target timeline changes while the backup is taken.
+	 * But they are small and highly useful for debugging purposes, so
+	 * better include them all, always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index d519252aad..5b0aa8ae85 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 									 bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
+extern void collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+							   bool infotbssize, bool needtblspcmapfile);
 extern void do_pg_abort_backup(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.0 (Apple Git-122.2)

0005-pg_basebackup-changes-for-parallel-backup_v6.patchapplication/octet-stream; name=0005-pg_basebackup-changes-for-parallel-backup_v6.patchDownload
From d4663820abbec2944e5c65500e574691a251e170 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 14 Oct 2019 17:28:58 +0500
Subject: [PATCH 5/7] pg_basebackup changes for parallel backup.

---
 src/bin/pg_basebackup/pg_basebackup.c | 736 ++++++++++++++++++++++++--
 1 file changed, 689 insertions(+), 47 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index a9d162a7da..f63c106130 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -19,6 +19,7 @@
 #include <sys/wait.h>
 #include <signal.h>
 #include <time.h>
+#include <pthread.h>
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -41,6 +42,7 @@
 #include "receivelog.h"
 #include "replication/basebackup.h"
 #include "streamutil.h"
+#include "fe_utils/simple_list.h"
 
 #define ERRCODE_DATA_CORRUPTED	"XX001"
 
@@ -57,6 +59,57 @@ typedef struct TablespaceList
 	TablespaceListCell *tail;
 } TablespaceList;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+
+	int			tsIndex;	/* index of tsInfo this file belongs to. */
+} BackupFile;
+
+typedef struct
+{
+	Oid			tblspcOid;
+	char	   *tablespace;	 /* tablespace name or NULL if 'base' tablespace */
+	int			numFiles;	 /* number of files */
+	BackupFile *backupFiles; /* list of files in a tablespace */
+} TablespaceInfo;
+
+typedef struct
+{
+	int 	tablespacecount;
+	int		totalfiles;
+	int		numWorkers;
+
+	char	xlogstart[64];
+	char   *backup_label;
+	char   *tablespace_map;
+
+	TablespaceInfo *tsInfo;
+	BackupFile	  **files;		/* list of BackupFile pointers */
+	int				fileIndex;	/* index of file to be fetched */
+
+	PGconn	**workerConns;
+} BackupInfo;
+
+typedef struct
+{
+	BackupInfo *backupInfo;
+	uint64		bytesRead;
+
+	int			workerid;
+	pthread_t	worker;
+
+	bool	terminated;
+} WorkerState;
+
+BackupInfo *backupInfo = NULL;
+WorkerState *workers = NULL;
+
+static pthread_mutex_t fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -110,6 +163,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -140,9 +196,10 @@ static PQExpBuffer recoveryconfcontents = NULL;
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
+static void workers_progress_report(uint64 totalBytesRead, const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
-static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
+static int	ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void BaseBackup(void);
 
 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -151,6 +208,17 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupRun(BackupInfo *backupInfo);
+static void StopBackup(BackupInfo *backupInfo);
+static void GetBackupFileList(PGconn *conn, BackupInfo *backupInfo);
+static int GetBackupFile(WorkerState *wstate);
+static BackupFile *getNextFile(BackupInfo *backupInfo);
+static int	compareFileSize(const void *a, const void *b);
+static void read_label_tblspcmap(PGconn *conn, char **backup_label, char **tablespace_map);
+static void create_backup_dirs(bool basetablespace, char *tablespace, char *name);
+static void writefile(char *path, char *buf);
+static void *workerRun(void *arg);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -202,6 +270,17 @@ cleanup_directories_atexit(void)
 static void
 disconnect_atexit(void)
 {
+	/* close worker connections */
+	if (backupInfo && backupInfo->workerConns != NULL)
+	{
+		int i;
+		for (i = 0; i < numWorkers; i++)
+		{
+			if (backupInfo->workerConns[i] != NULL)
+				PQfinish(backupInfo->workerConns[i]);
+		}
+	}
+
 	if (conn != NULL)
 		PQfinish(conn);
 }
@@ -349,6 +428,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -695,6 +775,93 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 	}
 }
 
+/*
+ * Print a progress report of worker threads. If verbose output
+ * is enabled, also print the current file name.
+ *
+ * Progress report is written at maximum once per second, unless the
+ * force parameter is set to true.
+ */
+static void
+workers_progress_report(uint64 totalBytesRead, const char *filename, bool force)
+{
+	int			percent;
+	char		totalBytesRead_str[32];
+	char		totalsize_str[32];
+	pg_time_t	now;
+
+	if (!showprogress)
+		return;
+
+	now = time(NULL);
+	if (now == last_progress_report && !force)
+		return;					/* Max once per second */
+
+	last_progress_report = now;
+	percent = totalsize_kb ? (int) ((totalBytesRead / 1024) * 100 / totalsize_kb) : 0;
+
+	/*
+	 * Avoid overflowing past 100% or the full size. This may make the total
+	 * size number change as we approach the end of the backup (the estimate
+	 * will always be wrong if WAL is included), but that's better than having
+	 * the done column be bigger than the total.
+	 */
+	if (percent > 100)
+		percent = 100;
+	if (totalBytesRead / 1024 > totalsize_kb)
+		totalsize_kb = totalBytesRead / 1024;
+
+	/*
+	 * Separate step to keep platform-dependent format code out of
+	 * translatable strings.  And we only test for INT64_FORMAT availability
+	 * in snprintf, not fprintf.
+	 */
+	snprintf(totalBytesRead_str, sizeof(totalBytesRead_str), INT64_FORMAT,
+			 totalBytesRead / 1024);
+	snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
+
+#define VERBOSE_FILENAME_LENGTH 35
+
+	if (verbose)
+	{
+		if (!filename)
+
+			/*
+			 * No filename given, so clear the status line (used for last
+			 * call)
+			 */
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied %*s"),
+					(int) strlen(totalsize_str),
+					totalBytesRead_str, totalsize_str,
+					percent,
+					VERBOSE_FILENAME_LENGTH + 5, "");
+		else
+		{
+			bool		truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied, current file (%s%-*.*s)"),
+					(int) strlen(totalsize_str), totalBytesRead_str, totalsize_str,
+					percent,
+					/* Prefix with "..." if we do leading truncation */
+							truncate ? "..." : "",
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+							truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+					/* Truncate filename at beginning if it's too long */
+							truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+				(int) strlen(totalsize_str),
+				totalBytesRead_str, totalsize_str,
+				percent);
+	}
+
+	if (isatty(fileno(stderr)))
+		fprintf(stderr, "\r");
+	else
+		fprintf(stderr, "\n");
+}
 
 /*
  * Print a progress report based on the global variables. If verbose output
@@ -711,7 +878,7 @@ progress_report(int tablespacenum, const char *filename, bool force)
 	char		totalsize_str[32];
 	pg_time_t	now;
 
-	if (!showprogress)
+	if (!showprogress || numWorkers > 1)
 		return;
 
 	now = time(NULL);
@@ -1381,7 +1548,7 @@ get_tablespace_mapping(const char *dir)
  * specified directory. If it's for another tablespace, it will be restored
  * in the original or mapped directory.
  */
-static void
+static int
 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 {
 	char		current_path[MAXPGPATH];
@@ -1392,6 +1559,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	bool		basetablespace;
 	char	   *copybuf = NULL;
 	FILE	   *file = NULL;
+	int			readBytes = 0;
 
 	basetablespace = PQgetisnull(res, rownum, 0);
 	if (basetablespace)
@@ -1455,7 +1623,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("invalid tar block header size: %d", r);
 				exit(1);
 			}
-			totaldone += 512;
+			readBytes += 512;
 
 			current_len_left = read_tar_number(&copybuf[124], 12);
 
@@ -1486,21 +1654,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 					 * Directory
 					 */
 					filename[strlen(filename) - 1] = '\0';	/* Remove trailing slash */
+
+					/*
+					 * In parallel mode, we create directories before fetching
+					 * files so its Ok if a directory already exist.
+					 */
 					if (mkdir(filename, pg_dir_create_mode) != 0)
 					{
-						/*
-						 * When streaming WAL, pg_wal (or pg_xlog for pre-9.6
-						 * clusters) will have been created by the wal
-						 * receiver process. Also, when the WAL directory
-						 * location was specified, pg_wal (or pg_xlog) has
-						 * already been created as a symbolic link before
-						 * starting the actual backup. So just ignore creation
-						 * failures on related directories.
-						 */
-						if (!((pg_str_endswith(filename, "/pg_wal") ||
-							   pg_str_endswith(filename, "/pg_xlog") ||
-							   pg_str_endswith(filename, "/archive_status")) &&
-							  errno == EEXIST))
+						if (errno != EEXIST)
 						{
 							pg_log_error("could not create directory \"%s\": %m",
 										 filename);
@@ -1585,7 +1746,7 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				 */
 				fclose(file);
 				file = NULL;
-				totaldone += r;
+				readBytes += r;
 				continue;
 			}
 
@@ -1594,7 +1755,8 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 				pg_log_error("could not write to file \"%s\": %m", filename);
 				exit(1);
 			}
-			totaldone += r;
+			readBytes += r;
+			totaldone = readBytes;
 			progress_report(rownum, filename, false);
 
 			current_len_left -= r;
@@ -1622,13 +1784,11 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	if (copybuf != NULL)
 		PQfreemem(copybuf);
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
-
 	/*
 	 * No data is synced here, everything is done for all tablespaces at the
 	 * end.
 	 */
+	return readBytes;
 }
 
 
@@ -1715,16 +1875,28 @@ BaseBackup(void)
 			fprintf(stderr, "\n");
 	}
 
-	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
-				 escaped_label,
-				 showprogress ? "PROGRESS" : "",
-				 includewal == FETCH_WAL ? "WAL" : "",
-				 fastcheckpoint ? "FAST" : "",
-				 includewal == NO_WAL ? "" : "NOWAIT",
-				 maxrate_clause ? maxrate_clause : "",
-				 format == 't' ? "TABLESPACE_MAP" : "",
-				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	if (numWorkers <= 1)
+	{
+		basebkp =
+			psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 includewal == FETCH_WAL ? "WAL" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 includewal == NO_WAL ? "" : "NOWAIT",
+					 maxrate_clause ? maxrate_clause : "",
+					 format == 't' ? "TABLESPACE_MAP" : "",
+					 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	}
+	else
+	{
+		basebkp =
+			psprintf("START_BACKUP LABEL '%s' %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 format == 't' ? "TABLESPACE_MAP" : "");
+	}
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
@@ -1774,7 +1946,7 @@ BaseBackup(void)
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1830,24 +2002,74 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		int j = 0,
+			k = 0;
 
-	if (showprogress)
+		backupInfo = palloc0(sizeof(BackupInfo));
+		backupInfo->workerConns = (PGconn **) palloc0(sizeof(PGconn *) * numWorkers);
+		backupInfo->tablespacecount = tablespacecount;
+		backupInfo->numWorkers = numWorkers;
+		strlcpy(backupInfo->xlogstart, xlogstart, sizeof(backupInfo->xlogstart));
+
+		read_label_tblspcmap(conn, &backupInfo->backup_label, &backupInfo->tablespace_map);
+
+		/* retrieve backup file list from the server. **/
+		GetBackupFileList(conn, backupInfo);
+
+		/*
+		 * add backup_label in backup, (for tar format, ReceiveTarFile() will
+		 * take care of it).
+		 */
+		if (format == 'p')
+			writefile("backup_label", backupInfo->backup_label);
+
+		/*
+		 * Flatten the file list to avoid unnecessary locks and enable the sequential
+		 * access to file list. (Creating an array of BackupFile structre pointers).
+		 */
+		backupInfo->files =
+			(BackupFile **) palloc0(sizeof(BackupFile *) * backupInfo->totalfiles);
+		for (i = 0; i < backupInfo->tablespacecount; i++)
+		{
+			TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+
+			for (j = 0; j < curTsInfo->numFiles; j++)
+			{
+				backupInfo->files[k] = &curTsInfo->backupFiles[j];
+				k++;
+			}
+		}
+
+		ParallelBackupRun(backupInfo);
+		StopBackup(backupInfo);
+	}
+	else
 	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+
+		if (showprogress)
+		{
+			progress_report(PQntuples(tablespacehdr), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
 	}
 
+	/* Write recovery contents */
+	if (format == 'p' && writerecoveryconf)
+		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
+
 	PQclear(res);
 
 	/*
@@ -2043,6 +2265,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2070,7 +2293,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2211,6 +2434,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2325,6 +2551,22 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (format != 'p' && numWorkers > 1)
+	{
+		pg_log_error("parallel jobs are only supported with 'plain' format");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2397,3 +2639,403 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+/*
+ * Thread worker
+ */
+static void *
+workerRun(void *arg)
+{
+	WorkerState *wstate = (WorkerState *) arg;
+
+	GetBackupFile(wstate);
+
+	wstate->terminated = true;
+	return NULL;
+}
+
+/*
+ * Runs the worker threads and updates progress until all workers have
+ * terminated/completed.
+ */
+static void
+ParallelBackupRun(BackupInfo *backupInfo)
+{
+	int		status,
+			i;
+	bool	threadsActive = true;
+	uint64	totalBytes = 0;
+
+	workers = (WorkerState *) palloc0(sizeof(WorkerState) * numWorkers);
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		WorkerState *worker = &workers[i];
+
+		worker->backupInfo = backupInfo;
+		worker->workerid = i;
+		worker->bytesRead = 0;
+		worker->terminated = false;
+
+		backupInfo->workerConns[i] = GetConnection();
+		status = pthread_create(&worker->worker, NULL, workerRun, worker);
+		if (status != 0)
+		{
+			pg_log_error("failed to create thread: %m");
+			exit(1);
+		}
+
+		if (verbose)
+			pg_log_info("backup worker (%d) created, %d", i, status);
+	}
+
+	/*
+	 * This is the main thread for updating progrsss. It waits for workers to
+	 * complete and gets updated status during every loop iteration.
+	 */
+	while(threadsActive)
+	{
+		char *filename = NULL;
+
+		threadsActive = false;
+		totalBytes = 0;
+
+		for (i = 0; i < numWorkers; i++)
+		{
+			WorkerState *worker = &workers[i];
+
+			totalBytes += worker->bytesRead;
+			threadsActive |= !worker->terminated;
+		}
+
+		if (backupInfo->fileIndex < backupInfo->totalfiles)
+			filename = backupInfo->files[backupInfo->fileIndex]->path;
+
+		workers_progress_report(totalBytes, filename, false);
+		pg_usleep(100000);
+	}
+
+	if (showprogress)
+	{
+		workers_progress_report(totalBytes, NULL, true);
+		if (isatty(fileno(stderr)))
+			fprintf(stderr, "\n");	/* Need to move to next line */
+	}
+}
+
+/*
+ * Take the system out of backup mode.
+ */
+static void
+StopBackup(BackupInfo *backupInfo)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP LABEL '%s' %s %s",
+					   backupInfo->backup_label,
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+	PQclear(res);
+}
+
+/*
+ * Retrive backup file list from the server and populate TablespaceInfo struct
+ * to keep track of tablespaces and its files.
+ */
+static void
+GetBackupFileList(PGconn *conn, BackupInfo *backupInfo)
+{
+	TablespaceInfo	*tsInfo;
+	PGresult   *res = NULL;
+	char	   *basebkp;
+	int			i;
+
+	backupInfo->tsInfo = palloc0(sizeof(TablespaceInfo) * backupInfo->tablespacecount);
+	tsInfo = backupInfo->tsInfo;
+
+	/*
+	 * Get list of files.
+	 */
+	basebkp = psprintf("SEND_BACKUP_FILELIST");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SEND_BACKUP_FILELIST", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * The list of files is grouped by tablespaces, and we want to fetch them
+	 * in the same order.
+	 */
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		bool		basetablespace;
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tsInfo[i].tblspcOid = atol(PQgetvalue(tablespacehdr, i, 0));
+		tsInfo[i].tablespace = PQgetvalue(tablespacehdr, i, 1);
+		tsInfo[i].numFiles = PQntuples(res);
+		tsInfo[i].backupFiles = palloc0(sizeof(BackupFile) * tsInfo[i].numFiles);
+
+		/* keep count of all files in backup */
+		backupInfo->totalfiles += tsInfo[i].numFiles;
+
+		for (int j = 0; j < tsInfo[i].numFiles; j++)
+		{
+			char	   *path = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+				create_backup_dirs(basetablespace, tsInfo[i].tablespace, path);
+
+			strlcpy(tsInfo[i].backupFiles[j].path, path, MAXPGPATH);
+			tsInfo[i].backupFiles[j].type = type;
+			tsInfo[i].backupFiles[j].size = size;
+			tsInfo[i].backupFiles[j].mtime = mtime;
+			tsInfo[i].backupFiles[j].tsIndex = i;
+		}
+
+		/* sort files in descending order, based on size */
+		qsort(tsInfo[i].backupFiles, tsInfo[i].numFiles,
+			  sizeof(BackupFile), &compareFileSize);
+		PQclear(res);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+}
+
+/*
+ * Retrive and write backup file from the server. The file list is provided by
+ * worker state. It pulls a single file from this list and writes it to the
+ * backup directory.
+ */
+static int
+GetBackupFile(WorkerState *wstate)
+{
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn = NULL;
+	BackupFile *fetchFile = NULL;
+	BackupInfo *backupInfo = NULL;
+
+	backupInfo = wstate->backupInfo;
+	worker_conn = backupInfo->workerConns[wstate->workerid];
+	while ((fetchFile = getNextFile(backupInfo)) != NULL)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+
+		/*
+		 * build query in form of: SEND_BACKUP_FILES ('base/1/1245/32683',
+		 * 'base/1/1245/32683', ...) [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_BACKUP_FILES ( '%s' )", fetchFile->path);
+
+		/* add options */
+		appendPQExpBuffer(buf, " START_WAL_LOCATION '%s' %s %s",
+						  backupInfo->xlogstart,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+
+		destroyPQExpBuffer(buf);
+
+		/* process file contents, also count bytesRead for progress */
+		wstate->bytesRead +=
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, fetchFile->tsIndex);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	return 0;
+}
+
+/*
+ * Increment fileIndex and store it in a local variable so that even a
+ * context switch does not affect the file index value and we don't accidentally
+ * increment the value twice and therefore skip some files.
+ */
+static BackupFile*
+getNextFile(BackupInfo *backupInfo)
+{
+	int fileIndex = 0;
+
+	pthread_mutex_lock(&fetch_mutex);
+	fileIndex = backupInfo->fileIndex++;
+	pthread_mutex_unlock(&fetch_mutex);
+
+	if (fileIndex >= backupInfo->totalfiles)
+		return NULL;
+
+	return backupInfo->files[fileIndex];
+}
+
+/* qsort comparator for BackupFile (sort descending order)  */
+static int
+compareFileSize(const void *a, const void *b)
+{
+	const		BackupFile *v1 = (BackupFile *) a;
+	const		BackupFile *v2 = (BackupFile *) b;
+
+	if (v1->size > v2->size)
+		return -1;
+	if (v1->size < v2->size)
+		return 1;
+
+	return 0;
+}
+
+static void
+read_label_tblspcmap(PGconn *conn, char **backuplabel, char **tblspc_map)
+{
+	PGresult   *res = NULL;
+
+	Assert(backuplabel != NULL);
+	Assert(tblspc_map != NULL);
+
+	/*
+	 * Get Backup label and tablespace map data.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) < 1)
+	{
+		pg_log_error("no data returned from server");
+		exit(1);
+	}
+
+	*backuplabel = PQgetvalue(res, 0, 0);	/* backup_label */
+	if (!PQgetisnull(res, 0, 1))
+		*tblspc_map = PQgetvalue(res, 0, 1);	/* tablespace_map */
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	PQclear(res);
+}
+
+/*
+ * Create backup direcotries while taking care of tablespace path. If tablespace
+ * mapping (with -T) is given then the directory will be created on the mapped
+ * path.
+ */
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char	dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+/*
+ * General function for writing to a file; creates one if it doesn't exist
+ */
+static void
+writefile(char *path, char *buf)
+{
+	FILE   *f;
+	char	pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
-- 
2.21.0 (Apple Git-122.2)

0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v6.patchapplication/octet-stream; name=0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v6.patchDownload
From 3e02fe0d50c1dfdcb708e105af475ed53877efd0 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 16:45:28 +0500
Subject: [PATCH 2/7] Rename sizeonly to dryrun for few functions in
 basebackup.

---
 src/backend/replication/basebackup.c | 44 ++++++++++++++--------------
 src/include/replication/basebackup.h |  2 +-
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 71a8b4fb4c..267163ed29 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -54,15 +54,15 @@ typedef struct
 } basebackup_options;
 
 
-static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
+static int64 sendDir(const char *path, int basepathlen, bool dryrun,
 					 List *tablespaces, bool sendtblspclinks);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
 static int64 _tarWriteHeader(const char *filename, const char *linktarget,
-							 struct stat *statbuf, bool sizeonly);
+							 struct stat *statbuf, bool dryrun);
 static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-						  bool sizeonly);
+						  bool dryrun);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
@@ -959,13 +959,13 @@ sendFileWithContent(const char *filename, const char *content)
 
 /*
  * Include the tablespace directory pointed to by 'path' in the output tar
- * stream.  If 'sizeonly' is true, we just calculate a total length and return
+ * stream.  If 'dryrun' is true, we just calculate a total length and return
  * it, without actually sending anything.
  *
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool dryrun)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -995,17 +995,17 @@ sendTablespace(char *path, bool sizeonly)
 	}
 
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
-						   sizeonly);
+						   dryrun);
 
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
 
 	return size;
 }
 
 /*
  * Include all files from the given directory in the output tar stream. If
- * 'sizeonly' is true, we just calculate a total length and return it, without
+ * 'dryrun' is true, we just calculate a total length and return it, without
  * actually sending anything.
  *
  * Omit any directory in the tablespaces list, to avoid backing up
@@ -1016,7 +1016,7 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		bool sendtblspclinks)
 {
 	DIR		   *dir;
@@ -1171,7 +1171,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
-				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
 			}
@@ -1187,7 +1187,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
 
@@ -1199,14 +1199,14 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (strcmp(pathbuf, "./pg_wal") == 0)
 		{
 			/* If pg_wal is a symlink, write it as a directory anyway */
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 
 			/*
 			 * Also send archive_status directory (by hackishly reusing
 			 * statbuf from above ...).
 			 */
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			continue;			/* don't recurse into pg_wal */
 		}
@@ -1238,7 +1238,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			linkpath[rllen] = '\0';
 
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
-									&statbuf, sizeonly);
+									&statbuf, dryrun);
 #else
 
 			/*
@@ -1262,7 +1262,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 * permissions right.
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1293,17 +1293,17 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			if (!dryrun)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
-			if (sent || sizeonly)
+			if (sent || dryrun)
 			{
 				/* Add size, rounded up to 512byte block */
 				size += ((statbuf.st_size + 511) & ~511);
@@ -1612,12 +1612,12 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
 
 static int64
 _tarWriteHeader(const char *filename, const char *linktarget,
-				struct stat *statbuf, bool sizeonly)
+				struct stat *statbuf, bool dryrun)
 {
 	char		h[512];
 	enum tarError rc;
 
-	if (!sizeonly)
+	if (!dryrun)
 	{
 		rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
 							 statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
@@ -1654,7 +1654,7 @@ _tarWriteHeader(const char *filename, const char *linktarget,
  */
 static int64
 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-			 bool sizeonly)
+			 bool dryrun)
 {
 	/* If symlink, write it as a directory anyway */
 #ifndef WIN32
@@ -1664,7 +1664,7 @@ _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
 #endif
 		statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
 
-	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
+	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, dryrun);
 }
 
 /*
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..b55917b9b6 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool dryrun);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122.2)

0004-backend-changes-for-parallel-backup_v6.patchapplication/octet-stream; name=0004-backend-changes-for-parallel-backup_v6.patchDownload
From e49af53b950e2cfa5a38ad4a5db21651f1374c59 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 22:59:28 +0500
Subject: [PATCH 4/7] backend changes for parallel backup

---
 src/backend/access/transam/xlog.c      |   2 +-
 src/backend/replication/basebackup.c   | 541 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    | 206 ++++++++--
 src/backend/replication/repl_scanner.l |   6 +
 src/include/nodes/replnodes.h          |  10 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 717 insertions(+), 50 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 451fe6c0d1..445aad291e 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -12279,7 +12279,7 @@ collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index b679f36021..e55b156092 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -41,6 +41,7 @@
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
+#include "utils/pg_lsn.h"
 
 typedef struct
 {
@@ -51,11 +52,20 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	XLogRecPtr	wal_location;
 } basebackup_options;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+} BackupFile;
+
 
 static int64 sendDir(const char *path, int basepathlen, bool dryrun,
-					 List *tablespaces, bool sendtblspclinks);
+					 List *tablespaces, bool sendtblspclinks, List **filelist);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -75,6 +85,13 @@ static void throttle(size_t increment);
 static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendBackupFileList(void);
+static void SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok);
+static void addToBackupFileList(List **filelist, char *path, char type, int32 size,
+								time_t mtime);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -289,7 +306,7 @@ perform_base_backup(basebackup_options *opt)
 
 	/* Add a node for the base directory at the end */
 	ti = palloc0(sizeof(tablespaceinfo));
-	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
 	tablespaces = lappend(tablespaces, ti);
 
 	/* Send tablespace header */
@@ -323,10 +340,10 @@ perform_base_backup(basebackup_options *opt)
 			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
 				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-				sendDir(".", 1, false, tablespaces, false);
+				sendDir(".", 1, false, tablespaces, false, NULL);
 			}
 			else
-				sendDir(".", 1, false, tablespaces, true);
+				sendDir(".", 1, false, tablespaces, true, NULL);
 
 			/* ... and pg_control after everything else. */
 			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -337,7 +354,7 @@ perform_base_backup(basebackup_options *opt)
 			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
 		else
-			sendTablespace(ti->path, false);
+			sendTablespace(ti->path, false, NULL);
 
 		/*
 		 * If we're including WAL, and this is the main data directory we
@@ -409,6 +426,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_wal_location = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -497,12 +515,24 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "start_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *wal_location;
+
+			if (o_wal_location)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			wal_location = strVal(defel->arg);
+			opt->wal_location = pg_lsn_in_internal(wal_location, &have_error);
+			o_wal_location = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
 	}
-	if (opt->label == NULL)
-		opt->label = "base backup";
 }
 
 
@@ -520,6 +550,15 @@ SendBaseBackup(BaseBackupCmd *cmd)
 
 	parse_basebackup_options(cmd->options, &opt);
 
+	/* default value for label, if not specified. */
+	if (opt.label == NULL)
+	{
+		if (cmd->cmdtag == BASE_BACKUP)
+			opt.label = "base backup";
+		else
+			opt.label = "start backup";
+	}
+
 	WalSndSetState(WALSNDSTATE_BACKUP);
 
 	if (update_process_title)
@@ -531,7 +570,29 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_BACKUP_FILELIST:
+			SendBackupFileList();
+			break;
+		case SEND_BACKUP_FILES:
+			SendBackupFiles(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -674,6 +735,61 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_puttextmessage('C', "SELECT");
 }
 
+/*
+ * Send a single resultset containing backup label and tablespace map
+ */
+static void
+SendStartBackupResult(StringInfo labelfile, StringInfo tblspc_map_file)
+{
+	StringInfoData buf;
+	Size		len;
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);		/* 2 fields */
+
+	/* Field headers */
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "tablespacemap");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint16(&buf, 2);		/* number of columns */
+
+	len = labelfile->len;
+	pq_sendint32(&buf, len);
+	pq_sendbytes(&buf, labelfile->data, len);
+
+	if (tblspc_map_file)
+	{
+		len = tblspc_map_file->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, tblspc_map_file->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
+	}
+
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -725,7 +841,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool dryrun)
+sendTablespace(char *path, bool dryrun, List **filelist)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -754,11 +870,11 @@ sendTablespace(char *path, bool dryrun)
 		return 0;
 	}
 
+	addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   dryrun);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true, filelist);
 
 	return size;
 }
@@ -777,7 +893,7 @@ sendTablespace(char *path, bool dryrun)
  */
 static int64
 sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
-		bool sendtblspclinks)
+		bool sendtblspclinks, List **filelist)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -931,6 +1047,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
@@ -947,6 +1065,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
@@ -968,6 +1088,10 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									dryrun);
 
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
+			addToBackupFileList(filelist, "./pg_wal/archive_status", 'd', -1,
+								statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -997,6 +1121,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			addToBackupFileList(filelist, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, dryrun);
 #else
@@ -1023,6 +1148,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									dryrun);
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1053,13 +1179,15 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks, filelist);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!dryrun)
+			addToBackupFileList(filelist, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!dryrun && filelist == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1764,3 +1892,388 @@ setup_throttle(int maxrate)
 		throttling_counter = -1;
 	}
 }
+
+/*
+ * StartBackup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+	tablespaceinfo *ti;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, register base_backup_cleanup with before_shmem_exit handler. This
+	 * will make sure that call is always made when process exits. In success,
+	 * do_pg_stop_backup will have taken the system out of backup mode and this
+	 * callback will have no effect, Otherwise the required cleanup will be done
+	 * in any case.
+	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
+
+	SendXlogRecPtrResult(startptr, starttli);
+
+	/*
+	 * Calculate the relative path of temporary statistics directory in
+	 * order to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
+	tablespaces = lappend(tablespaces, ti);
+
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
+		!opt->sendtblspcmapfile)
+		tblspc_map_file = NULL;
+
+	/* send backup_label and tablespace_map to frontend */
+	SendStartBackupResult(labelfile, tblspc_map_file);
+}
+
+/*
+ * StopBackup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionaly WAL segments and ending WAL location.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile = NULL;
+
+	if (get_backup_status() != SESSION_BACKUP_NON_EXCLUSIVE)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("non-exclusive backup is not in progress")));
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	/* stop backup */
+	labelfile = (char *) opt->label;
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	if (opt->includewal)
+		include_wal_files(endptr);
+
+	pq_putemptymessage('c');	/* CopyDone */
+	SendXlogRecPtrResult(endptr, endtli);
+}
+
+/*
+ * SendBackupFileList() - sends a list of filenames to frontend
+ *
+ * The function collects a list of filenames, necessary for a complete backup and
+ * sends this list to the client.
+ */
+static void
+SendBackupFileList(void)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	List	   *tablespaces = NIL;
+	StringInfo	tblspc_map_file = NULL;
+	tablespaceinfo *ti;
+
+	tblspc_map_file = makeStringInfo();
+	collectTablespaces(&tablespaces, tblspc_map_file, false, false);
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	tablespaces = lappend(tablespaces, ti);
+
+	foreach(lc, tablespaces)
+	{
+		List	   *filelist = NULL;
+		tablespaceinfo *ti;
+
+		ti = (tablespaceinfo *) lfirst(lc);
+		if (ti->path == NULL)
+			sendDir(".", 1, true, NIL, true, &filelist);
+		else
+			sendTablespace(ti->path, true, &filelist);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 4);	/* n field */
+
+		/* First field - file name */
+		pq_sendstring(&buf, "path");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "type");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, CHAROID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - mtime */
+		pq_sendstring(&buf, "mtime");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, filelist)
+		{
+			BackupFile *backupFile = (BackupFile *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 4);	/* number of columns */
+
+			/* send path */
+			len = strlen(backupFile->path);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, backupFile->path, len);
+
+			/* send type */
+			pq_sendint32(&buf, 1);
+			pq_sendbyte(&buf, backupFile->type);
+
+			/* send size */
+			send_int8_string(&buf, backupFile->size);
+
+			/* send mtime */
+			send_int8_string(&buf, backupFile->mtime);
+
+			pq_endmessage(&buf);
+		}
+
+		if (filelist)
+			pfree(filelist);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendBackupFiles() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol.
+ */
+static void
+SendBackupFiles(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	int			basepathlen = 1;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/* set backup start location. */
+	startptr = opt->wal_location;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (is_absolute_path(pathbuf))
+		{
+			char *basepath;
+
+			/*
+			 * 'pathbuf' points to the tablespace location, but we only want to
+			 * include the version directory in it that belongs to us.
+			 */
+			basepath = strstr(pathbuf, TABLESPACE_VERSION_DIRECTORY);
+			if (basepath)
+				basepathlen  = basepath - pathbuf - 1;
+		}
+
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/* Allow symbolic links in pg_tblspc only */
+		if (strstr(pathbuf, "./pg_tblspc") != NULL &&
+#ifndef WIN32
+			S_ISLNK(statbuf.st_mode)
+#else
+			pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			char		linkpath[MAXPGPATH];
+			int			rllen;
+
+			rllen = readlink(pathbuf, linkpath, sizeof(linkpath));
+			if (rllen < 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not read symbolic link \"%s\": %m",
+								pathbuf)));
+			if (rllen >= sizeof(linkpath))
+				ereport(ERROR,
+						(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+						 errmsg("symbolic link \"%s\" target is too long",
+								pathbuf)));
+			linkpath[rllen] = '\0';
+
+			_tarWriteHeader(pathbuf, linkpath, &statbuf, false);
+		}
+		else if (S_ISDIR(statbuf.st_mode))
+		{
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else if (
+#ifndef WIN32
+				 S_ISLNK(statbuf.st_mode)
+#else
+				 pgwin32_is_junction(pathbuf)
+#endif
+			)
+		{
+			/*
+			 * If symlink, write it as a directory. file symlinks only allowed
+			 * in pg_tblspc
+			 */
+			statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+			_tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf, false);
+		}
+		else
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report total checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+/*
+ * Construct a BackupFile entry and add to the list.
+ */
+static void
+addToBackupFileList(List **filelist,  char *path, char type, int32 size,
+					time_t mtime)
+{
+	BackupFile *backupFile;
+
+	if (filelist)
+	{
+		backupFile = (BackupFile *) palloc0(sizeof(BackupFile));
+		strlcpy(backupFile->path, path, sizeof(backupFile->path));
+		backupFile->type = type;
+		backupFile->size = size;
+		backupFile->mtime = mtime;
+
+		*filelist = lappend(*filelist, backupFile);
+	}
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..225c35efdb 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,13 +87,24 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_BACKUP_FILELIST
+%token K_SEND_BACKUP_FILES
+%token K_STOP_BACKUP
+%token K_START_WAL_LOCATION
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
 				create_replication_slot drop_replication_slot identify_system
 				timeline_history show sql_cmd
 %type <list>	base_backup_opt_list
+				start_backup_opt_list stop_backup_opt_list
+				send_backup_files_opt_list
 %type <defelt>	base_backup_opt
+				backup_opt_label backup_opt_progress backup_opt_maxrate
+				backup_opt_fast backup_opt_tsmap backup_opt_wal backup_opt_nowait
+				backup_opt_chksum backup_opt_wal_loc
+				start_backup_opt stop_backup_opt send_backup_files_opt
 %type <uintval>	opt_timeline
 %type <list>	plugin_options plugin_opt_list
 %type <defelt>	plugin_opt_elem
@@ -102,6 +113,8 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
+%type <node>	backup_file
 
 %%
 
@@ -162,10 +175,61 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_START_BACKUP start_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_FILELIST
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = NIL;
+					cmd->cmdtag = SEND_BACKUP_FILELIST;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_BACKUP_FILES backup_files send_backup_files_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_BACKUP_FILES;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP stop_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
 
+start_backup_opt_list:
+	start_backup_opt_list start_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+			;
+
+stop_backup_opt_list:
+	stop_backup_opt_list stop_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
+send_backup_files_opt_list:
+	send_backup_files_opt_list send_backup_files_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
 base_backup_opt_list:
 			base_backup_opt_list base_backup_opt
 				{ $$ = lappend($1, $2); }
@@ -173,49 +237,123 @@ base_backup_opt_list:
 				{ $$ = NIL; }
 			;
 
+start_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_progress	{ $$ = $1; }
+		| backup_opt_fast		{ $$ = $1; }
+		| backup_opt_tsmap		{ $$ = $1; }
+			;
+
+stop_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_wal 		{ $$ = $1; }
+		| backup_opt_nowait		{ $$ = $1; }
+			;
+
+send_backup_files_opt:
+			backup_opt_maxrate		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_wal_loc	{ $$ = $1; }
+			;
+
 base_backup_opt:
-			K_LABEL SCONST
-				{
-				  $$ = makeDefElem("label",
-								   (Node *)makeString($2), -1);
-				}
-			| K_PROGRESS
-				{
-				  $$ = makeDefElem("progress",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_FAST
-				{
-				  $$ = makeDefElem("fast",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_WAL
-				{
-				  $$ = makeDefElem("wal",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_NOWAIT
-				{
-				  $$ = makeDefElem("nowait",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_MAX_RATE UCONST
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_progress	{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			| backup_opt_wal 		{ $$ = $1; }
+			| backup_opt_nowait		{ $$ = $1; }
+			| backup_opt_maxrate	{ $$ = $1; }
+			| backup_opt_tsmap		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			;
+
+backup_opt_label:
+	K_LABEL SCONST
+	{
+	  $$ = makeDefElem("label",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_progress:
+	K_PROGRESS
+	{
+	  $$ = makeDefElem("progress",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_fast:
+	K_FAST
+	{
+	  $$ = makeDefElem("fast",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal:
+	K_WAL
+	{
+	  $$ = makeDefElem("wal",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_nowait:
+	K_NOWAIT
+	{
+	  $$ = makeDefElem("nowait",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_maxrate:
+	K_MAX_RATE UCONST
+	{
+	  $$ = makeDefElem("max_rate",
+					   (Node *)makeInteger($2), -1);
+	};
+
+backup_opt_tsmap:
+	K_TABLESPACE_MAP
+	{
+	  $$ = makeDefElem("tablespace_map",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_chksum:
+	K_NOVERIFY_CHECKSUMS
+	{
+	  $$ = makeDefElem("noverify_checksums",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal_loc:
+	K_START_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("start_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_files:
+			'(' backup_files_list ')'
 				{
-				  $$ = makeDefElem("max_rate",
-								   (Node *)makeInteger($2), -1);
+					$$ = $2;
 				}
-			| K_TABLESPACE_MAP
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			backup_file
 				{
-				  $$ = makeDefElem("tablespace_map",
-								   (Node *)makeInteger(true), -1);
+					$$ = list_make1($1);
 				}
-			| K_NOVERIFY_CHECKSUMS
+			| backup_files_list ',' backup_file
 				{
-				  $$ = makeDefElem("noverify_checksums",
-								   (Node *)makeInteger(true), -1);
+					$$ = lappend($1, $3);
 				}
 			;
 
+backup_file:
+			SCONST							{ $$ = (Node *) makeString($1); }
+			;
+
 create_replication_slot:
 			/* CREATE_REPLICATION_SLOT slot TEMPORARY PHYSICAL RESERVE_WAL */
 			K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL create_slot_opt_list
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..0a88639239 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,12 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_BACKUP_FILELIST	{ return K_SEND_BACKUP_FILELIST; }
+SEND_BACKUP_FILES	{ return K_SEND_BACKUP_FILES; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..3685f260b5 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,14 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_BACKUP_FILELIST,
+	SEND_BACKUP_FILES,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +50,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index b55917b9b6..5202e4160b 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool dryrun);
+extern int64 sendTablespace(char *path, bool dryrun, List **filelist);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122.2)

0006-parallel-backup-testcase_v6.patchapplication/octet-stream; name=0006-parallel-backup-testcase_v6.patchDownload
From a8c2207928c415421433a80492b2a1f7f7b3930e Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 6/7] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 527 ++++++++++++++++++
 1 file changed, 527 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..4ec4c1e0f6
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,527 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 95;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+#	# Create a temporary directory in the system location and symlink it
+#	# to our physical temp location.  That way we can use shorter names
+#	# for the tablespace directories, which hopefully won't run afoul of
+#	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+my $file;
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.0 (Apple Git-122.2)

0007-parallel-backup-documentation_v6.patchapplication/octet-stream; name=0007-parallel-backup-documentation_v6.patchDownload
From d81aad9f5e18004dc721cf0dcc108d9e797a0c20 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Thu, 7 Nov 2019 16:52:40 +0500
Subject: [PATCH 7/7] parallel backup documentation

---
 doc/src/sgml/protocol.sgml          | 386 ++++++++++++++++++++++++++++
 doc/src/sgml/ref/pg_basebackup.sgml |  20 ++
 2 files changed, 406 insertions(+)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 80275215e0..22d620c346 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2700,6 +2700,392 @@ The commands accepted in replication mode are:
      </para>
     </listitem>
   </varlistentry>
+  
+  <varlistentry>
+    <term><literal>START_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>PROGRESS</literal> ]
+        [ <literal>FAST</literal> ]
+        [ <literal>TABLESPACE_MAP</literal> ]
+
+     <indexterm><primary>START_BACKUP</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to prepare for performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><literal>LABEL</literal> <replaceable>'label'</replaceable></term>
+        <listitem>
+         <para>
+          Sets the label of the backup. If none is specified, a backup label
+          of <literal>start backup</literal> will be used. The quoting rules
+          for the label are the same as a standard SQL string with
+          <xref linkend="guc-standard-conforming-strings"/> turned on.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>PROGRESS</literal></term>
+        <listitem>
+         <para>
+          Request information required to generate a progress report. This will
+          send back an approximate size in the header of each tablespace, which
+          can be used to calculate how far along the stream is done. This is
+          calculated by enumerating all the file sizes once before the transfer
+          is even started, and might as such have a negative impact on the
+          performance.  In particular, it might take longer before the first data
+          is streamed. Since the database files can change during the backup,
+          the size is only approximate and might both grow and shrink between
+          the time of approximation and the sending of the actual files.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>FAST</literal></term>
+        <listitem>
+         <para>
+          Request a fast checkpoint.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>TABLESPACE_MAP</literal></term>
+        <listitem>
+         <para>
+          Include information about symbolic links present in the directory
+          <filename>pg_tblspc</filename> in a file named
+          <filename>tablespace_map</filename>. The tablespace map file includes
+          each symbolic link name as it exists in the directory
+          <filename>pg_tblspc/</filename> and the full path of that symbolic link.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     
+     <para>
+      In response to this command, server will send out three result sets.
+     </para>
+     <para>
+      The first ordinary result set contains the starting position of the
+      backup, in a single row with two columns. The first column contains
+      the start position given in XLogRecPtr format, and the second column
+      contains the corresponding timeline ID.
+     </para>
+     
+     <para>
+      The second ordinary result set has one row for each tablespace.
+      The fields in this row are:
+      <variablelist>
+       <varlistentry>
+        <term><literal>spcoid</literal> (<type>oid</type>)</term>
+        <listitem>
+         <para>
+          The OID of the tablespace, or null if it's the base
+          directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>spclocation</literal> (<type>text</type>)</term>
+        <listitem>
+         <para>
+          The full path of the tablespace directory, or null
+          if it's the base directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the tablespace, in kilobytes (1024 bytes),
+          if progress report has been requested; otherwise it's null.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+     <para>
+      The final result set will be sent in a single row with two columns. The
+      first column contains the data of <filename>backup_label</filename> file,
+      and the second column contains the data of <filename>tablespace_map</filename>.
+     </para>
+
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>STOP_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>WAL</literal> ]
+        [ <literal>NOWAIT</literal> ]
+
+     <indexterm><primary>STOP_BACKUP</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to finish performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><replaceable class="parameter">LABEL</replaceable><replaceable>'string'</replaceable></term>
+        <listitem>
+         <para>
+          Provides the content of backup_label file to the backup. The content are
+          the same that were returned by <command>START_BACKUP</command>.
+         </para>
+        </listitem>
+       </varlistentry>
+        <varlistentry>
+        <term><literal>WAL</literal></term>
+        <listitem>
+         <para>
+          Include the necessary WAL segments in the backup. This will include
+          all the files between start and stop backup in the
+          <filename>pg_wal</filename> directory of the base directory tar
+          file.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>NOWAIT</literal></term>
+        <listitem>
+         <para>
+          By default, the backup will wait until the last required WAL
+          segment has been archived, or emit a warning if log archiving is
+          not enabled. Specifying <literal>NOWAIT</literal> disables both
+          the waiting and the warning, leaving the client responsible for
+          ensuring the required log is available.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+     <para>
+      In response to this command, server will send one or more CopyResponse
+      results followed by a single result set, containing the WAL end position of
+      the backup. The CopyResponse contains <filename>pg_control</filename> and
+      WAL files, if stop backup is run with WAL option.
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_BACKUP_FILELIST</literal>
+        <indexterm><primary>SEND_BACKUP_FILELIST</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instruct the server to return a list of files and directories, available in
+      data directory. In response to this command, server will send one result set
+      per tablespace. The result sets consist of following fields:
+     </para>
+
+     <variablelist>
+      <varlistentry>
+       <term><literal>path</literal> (<type>text</type>)</term>
+       <listitem>
+        <para>
+         The path and name of the file. In case of tablespace, it is an absolute
+         path on the database server, however, in case of <filename>base</filename>
+         tablespace, it is relative to $PGDATA.
+        </para>
+       </listitem>
+      </varlistentry>
+    
+      <varlistentry>
+       <term><literal>type</literal> (<type>char</type>)</term>
+       <listitem>
+        <para>
+         A single character, identifing the type of file.
+         <itemizedlist spacing="compact" mark="bullet">
+          <listitem>
+           <para>
+            <literal>'f'</literal> - Regular file. Can be any relation or
+            non-relation file in $PGDATA.
+           </para>
+          </listitem>
+    
+          <listitem>
+           <para>
+            <literal>'d'</literal> - Directory.
+           </para>
+          </listitem>
+    
+          <listitem>
+           <para>
+            <literal>'l'</literal> - Symbolic link.
+           </para>
+          </listitem>
+         </itemizedlist>
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the file, in kilobytes (1024 bytes). It's null if
+          type is 'd' or 'l'.
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>mtime</literal> (<type>Int64</type>)</term>
+        <listitem>
+         <para>
+          The file or directory last modification time, as seconds since the Epoch.
+         </para>
+        </listitem>
+      </varlistentry>
+     </variablelist>
+
+      <para>
+       This list will contain all files and directories in the $PGDATA, regardless of
+       whether they are PostgreSQL files or other files added to the same directory.
+       The only excluded files are:
+       <itemizedlist spacing="compact" mark="bullet">
+        <listitem>
+         <para>
+          <filename>postmaster.pid</filename>
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>postmaster.opts</filename>
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_internal.init</filename> (found in multiple directories)
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Various temporary files and directories created during the operation
+          of the PostgreSQL server, such as any file or directory beginning
+          with <filename>pgsql_tmp</filename> and temporary relations.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Unlogged relations, except for the init fork which is required to
+          recreate the (empty) unlogged relation on recovery.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_wal</filename>, including subdirectories. If the backup is run
+          with WAL files included, a synthesized version of <filename>pg_wal</filename> will be
+          included, but it will only contain the files necessary for the
+          backup to work, not the rest of the contents.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_dynshmem</filename>, <filename>pg_notify</filename>,
+          <filename>pg_replslot</filename>, <filename>pg_serial</filename>,
+          <filename>pg_snapshots</filename>, <filename>pg_stat_tmp</filename>, and
+          <filename>pg_subtrans</filename> are copied as empty directories (even if
+          they are symbolic links).
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Files other than regular files and directories, such as symbolic
+          links (other than for the directories listed above) and special
+          device files, are skipped.  (Symbolic links
+          in <filename>pg_tblspc</filename> are maintained.)
+         </para>
+        </listitem>
+       </itemizedlist>
+       Owner, group, and file mode are set if the underlying file system on the server
+       supports it.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_BACKUP_FILES ( <replaceable class="parameter">'FILE'</replaceable> [, ...] )</literal>
+        [ <literal>MAX_RATE</literal> <replaceable>rate</replaceable> ]
+        [ <literal>NOVERIFY_CHECKSUMS</literal> ]
+        [ <literal>START_WAL_LOCATION</literal> ]
+
+        <indexterm><primary>SEND_BACKUP_FILES</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to send the contents of the requested FILE(s).
+     </para>
+      
+     <para>
+      A clause of the form <literal>SEND_BACKUP_FILES ( 'FILE', 'FILE', ... ) [OPTIONS]</literal>
+      is accepted where one or more FILE(s) can be requested.
+     </para>
+
+     <para>
+      In response to this command, one or more CopyResponse results will be sent,
+      one for each FILE requested. The data in the CopyResponse results will be
+      a tar format (following the “ustar interchange format” specified in the
+      POSIX 1003.1-2008 standard) dump of the tablespace contents, except that
+      the two trailing blocks of zeroes specified in the standard are omitted.
+     </para>
+
+     <para>
+      The following options are accepted:
+       <variablelist>
+        <varlistentry>
+         <term><literal>MAX_RATE</literal> <replaceable>rate</replaceable></term>
+         <listitem>
+          <para>
+           Limit (throttle) the maximum amount of data transferred from server
+           to client per unit of time. The expected unit is kilobytes per second.
+           If this option is specified, the value must either be equal to zero
+           or it must fall within the range from 32 kB through 1 GB (inclusive).
+           If zero is passed or the option is not specified, no restriction is
+           imposed on the transfer.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>NOVERIFY_CHECKSUMS</literal></term>
+         <listitem>
+          <para>
+           By default, checksums are verified during a base backup if they are
+           enabled. Specifying <literal>NOVERIFY_CHECKSUMS</literal> disables
+           this verification.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>START_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The starting WAL position when START BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+        </varlistentry>
+       </variablelist>
+     </para>
+    </listitem>
+  </varlistentry>
 </variablelist>
 
 </para>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index fc9e222f8d..339e68bda7 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -536,6 +536,26 @@ PostgreSQL documentation
        </para>
       </listitem>
      </varlistentry>
+     
+     <varlistentry>
+      <term><option>-j <replaceable class="parameter">n</replaceable></option></term>
+      <term><option>--jobs=<replaceable class="parameter">n</replaceable></option></term>
+      <listitem>
+       <para>
+        Create <replaceable class="parameter">n</replaceable> threads to copy
+        backup files from the database server. <application>pg_basebackup</application>
+        will open <replaceable class="parameter">n</replaceable> +1 connections
+        to the database. Therefore, the server must be configured with
+        <xref linkend="guc-max-wal-senders"/> set high enough to accommodate all
+        connections.
+       </para>
+       
+       <para>
+        parallel mode only works with plain format.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </para>
 
-- 
2.21.0 (Apple Git-122.2)

#35Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Asif Rehman (#34)
Re: WIP/PoC for parallel backup

On Wed, Nov 13, 2019 at 7:04 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Sorry, I sent the wrong patches. Please see the correct version of the
patches (_v6).

Review comments on these patches:

1.
+ XLogRecPtr wal_location;

Looking at the other field names in basebackup_options structure, let's use
wallocation instead. Or better startwallocation to be precise.

2.
+ int32 size;

Should we use size_t here?

3.
I am still not sure why we need SEND_BACKUP_FILELIST as a separate command.
Can't we return the file list with START_BACKUP itself?

4.
+        else if (
+#ifndef WIN32
+                 S_ISLNK(statbuf.st_mode)
+#else
+                 pgwin32_is_junction(pathbuf)
+#endif
+            )
+        {
+            /*
+             * If symlink, write it as a directory. file symlinks only
allowed
+             * in pg_tblspc
+             */
+            statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+            _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
false);
+        }

In normal backup mode, we skip the special file which is not a regular file
or
a directory or a symlink inside pg_tblspc. But in your patch, above code,
treats it as a directory. Should parallel backup too skip such special
files?

5.
Please keep header file inclusions in alphabetical order in basebackup.c and
pg_basebackup.c

6.
+        /*
+         * build query in form of: SEND_BACKUP_FILES ('base/1/1245/32683',
+         * 'base/1/1245/32683', ...) [options]
+         */

Please update these comments as we fetch one file at a time.

7.
+backup_file:
+            SCONST                            { $$ = (Node *)
makeString($1); }
+            ;
+

Instead of having this rule with only one constant terminal, we can use
SCONST directly in backup_files_list. However, I don't see any issue with
this approach either, just trying to reduce the rules.

8.
Please indent code within 80 char limit at all applicable places.

9.
Please fix following typos:

identifing => identifying
optionaly => optionally
structre => structure
progrsss => progress
Retrive => Retrieve
direcotries => directories

=====

The other mail thread related to backup manifest [1]/messages/by-id/CA+TgmoZV8dw1H2bzZ9xkKwdrk8+XYa+DC9H=F7heO2zna5T6qg@mail.gmail.com, is creating a
backup_manifest file and sends that to the client which has optional
checksum and other details including filename, file size, mtime, etc.
There is a patch on the same thread which is then validating the backup too.

Since this patch too gets a file list from the server and has similar
details (except checksum), can somehow parallel backup use the
backup-manifest
infrastructure from that patch?

When the parallel backup is in use, will there be a backup_manifest file
created too? I am just visualizing what will be the scenario when both these
features are checked-in.

[1]: /messages/by-id/CA+TgmoZV8dw1H2bzZ9xkKwdrk8+XYa+DC9H=F7heO2zna5T6qg@mail.gmail.com
/messages/by-id/CA+TgmoZV8dw1H2bzZ9xkKwdrk8+XYa+DC9H=F7heO2zna5T6qg@mail.gmail.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Thanks
--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

#36Robert Haas
robertmhaas@gmail.com
In reply to: Jeevan Chalke (#35)
Re: WIP/PoC for parallel backup

On Wed, Nov 27, 2019 at 3:38 AM Jeevan Chalke
<jeevan.chalke@enterprisedb.com> wrote:

I am still not sure why we need SEND_BACKUP_FILELIST as a separate command.
Can't we return the file list with START_BACKUP itself?

I had the same thought, but I think it's better to keep them separate.
Somebody might want to use the SEND_BACKUP_FILELIST command for
something other than a backup (I actually think it should be called
just SEND_FILE_LIST). Somebody might want to start a backup without
getting a file list because they're going to copy the files at the FS
level. Somebody might want to get a list of files to process after
somebody else has started the backup on another connection. Or maybe
nobody wants to do any of those things, but it doesn't seem to cost us
much of anything to split the commands, so I think we should.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#37Asif Rehman
asifr.rehman@gmail.com
In reply to: Jeevan Chalke (#35)
Re: WIP/PoC for parallel backup

On Wed, Nov 27, 2019 at 1:38 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

On Wed, Nov 13, 2019 at 7:04 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Sorry, I sent the wrong patches. Please see the correct version of the
patches (_v6).

Review comments on these patches:

1.
+ XLogRecPtr wal_location;

Looking at the other field names in basebackup_options structure, let's use
wallocation instead. Or better startwallocation to be precise.

2.
+ int32 size;

Should we use size_t here?

3.
I am still not sure why we need SEND_BACKUP_FILELIST as a separate command.
Can't we return the file list with START_BACKUP itself?

4.
+        else if (
+#ifndef WIN32
+                 S_ISLNK(statbuf.st_mode)
+#else
+                 pgwin32_is_junction(pathbuf)
+#endif
+            )
+        {
+            /*
+             * If symlink, write it as a directory. file symlinks only
allowed
+             * in pg_tblspc
+             */
+            statbuf.st_mode = S_IFDIR | pg_dir_create_mode;
+            _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
false);
+        }

In normal backup mode, we skip the special file which is not a regular
file or
a directory or a symlink inside pg_tblspc. But in your patch, above code,
treats it as a directory. Should parallel backup too skip such special
files?

Yeah going through the code again, I found it a little bit inconsistent. In
fact
SendBackupFiles function is supposed to send the files that were requested
of
it. However, currently is performing these tasks:

1) If the requested file were to be a directory, it will return a TAR
directory entry.
2) If the requested files were to be symlink inside pg_tblspc, it will
return the link path.
3) and as you pointed out above, if the requested files were a symlink
outside pg_tblspc
and inside PGDATA then it will return TAR directory entry.

I think that this function should not take care of any of the above.
Instead, it should
be the client (i.e. pg_basebackup) managing it. The SendBackupFiles should
only send the
regular files and ignore the request of any other kind, be it a directory
or symlink.

Any thoughts?

5.
Please keep header file inclusions in alphabetical order in basebackup.c
and
pg_basebackup.c

6.
+        /*
+         * build query in form of: SEND_BACKUP_FILES ('base/1/1245/32683',
+         * 'base/1/1245/32683', ...) [options]
+         */

Please update these comments as we fetch one file at a time.

7.
+backup_file:
+            SCONST                            { $$ = (Node *)
makeString($1); }
+            ;
+

Instead of having this rule with only one constant terminal, we can use
SCONST directly in backup_files_list. However, I don't see any issue with
this approach either, just trying to reduce the rules.

8.
Please indent code within 80 char limit at all applicable places.

9.
Please fix following typos:

identifing => identifying
optionaly => optionally
structre => structure
progrsss => progress
Retrive => Retrieve
direcotries => directories

=====

The other mail thread related to backup manifest [1], is creating a
backup_manifest file and sends that to the client which has optional
checksum and other details including filename, file size, mtime, etc.
There is a patch on the same thread which is then validating the backup
too.

Since this patch too gets a file list from the server and has similar
details (except checksum), can somehow parallel backup use the
backup-manifest
infrastructure from that patch?

This was discussed earlier in the thread, and as Robert suggested, it would
complicate the
code to no real benefit.

When the parallel backup is in use, will there be a backup_manifest file
created too? I am just visualizing what will be the scenario when both
these
features are checked-in.

Yes, I think it should. Since the full backup will have a manifest file,
there is no
reason for parallel backup to not support it.

I'll share the updated patch in the next couple of days.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#38Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#36)
Re: WIP/PoC for parallel backup

On Thu, Nov 28, 2019 at 12:57 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Wed, Nov 27, 2019 at 3:38 AM Jeevan Chalke
<jeevan.chalke@enterprisedb.com> wrote:

I am still not sure why we need SEND_BACKUP_FILELIST as a separate

command.

Can't we return the file list with START_BACKUP itself?

I had the same thought, but I think it's better to keep them separate.
Somebody might want to use the SEND_BACKUP_FILELIST command for
something other than a backup (I actually think it should be called
just SEND_FILE_LIST)

Sure. Thanks for the recommendation. To keep the function names in sync, I
intend to do following the
following renamings:
- SEND_BACKUP_FILES --> SEND_FILES
- SEND_BACKUP_FILELIST --> SEND_FILE_LIST

. Somebody might want to start a backup without

getting a file list because they're going to copy the files at the FS
level. Somebody might want to get a list of files to process after
somebody else has started the backup on another connection. Or maybe
nobody wants to do any of those things, but it doesn't seem to cost us
much of anything to split the commands, so I think we should.

+1

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#39Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#38)
7 attachment(s)
Re: WIP/PoC for parallel backup

On Tue, Dec 10, 2019 at 7:34 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Thu, Nov 28, 2019 at 12:57 AM Robert Haas <robertmhaas@gmail.com>
wrote:

On Wed, Nov 27, 2019 at 3:38 AM Jeevan Chalke
<jeevan.chalke@enterprisedb.com> wrote:

I am still not sure why we need SEND_BACKUP_FILELIST as a separate

command.

Can't we return the file list with START_BACKUP itself?

I had the same thought, but I think it's better to keep them separate.
Somebody might want to use the SEND_BACKUP_FILELIST command for
something other than a backup (I actually think it should be called
just SEND_FILE_LIST)

Sure. Thanks for the recommendation. To keep the function names in sync, I
intend to do following the
following renamings:
- SEND_BACKUP_FILES --> SEND_FILES
- SEND_BACKUP_FILELIST --> SEND_FILE_LIST

. Somebody might want to start a backup without

getting a file list because they're going to copy the files at the FS
level. Somebody might want to get a list of files to process after
somebody else has started the backup on another connection. Or maybe
nobody wants to do any of those things, but it doesn't seem to cost us
much of anything to split the commands, so I think we should.

+1

I have updated the patches (v7 attached) and have taken care of all issues
pointed by Jeevan, additionally
ran the pgindent on each patch. Furthermore, Command names have been
renamed as suggested and I
have simplified the SendFiles function. Client can only request the regular
files, any other kind such as
directories or symlinks will be skipped, the client will be responsible for
taking care of such.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0007-parallel-backup-documentation_v7.patchapplication/octet-stream; name=0007-parallel-backup-documentation_v7.patchDownload
From 63952eafd3d2dbda70535048dbed2815fc75c3d0 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Thu, 7 Nov 2019 16:52:40 +0500
Subject: [PATCH 7/7] parallel backup documentation

---
 doc/src/sgml/protocol.sgml          | 386 ++++++++++++++++++++++++++++
 doc/src/sgml/ref/pg_basebackup.sgml |  20 ++
 2 files changed, 406 insertions(+)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 80275215e0..d582209229 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2700,6 +2700,392 @@ The commands accepted in replication mode are:
      </para>
     </listitem>
   </varlistentry>
+  
+  <varlistentry>
+    <term><literal>START_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>PROGRESS</literal> ]
+        [ <literal>FAST</literal> ]
+        [ <literal>TABLESPACE_MAP</literal> ]
+
+     <indexterm><primary>START_BACKUP</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to prepare for performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><literal>LABEL</literal> <replaceable>'label'</replaceable></term>
+        <listitem>
+         <para>
+          Sets the label of the backup. If none is specified, a backup label
+          of <literal>start backup</literal> will be used. The quoting rules
+          for the label are the same as a standard SQL string with
+          <xref linkend="guc-standard-conforming-strings"/> turned on.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>PROGRESS</literal></term>
+        <listitem>
+         <para>
+          Request information required to generate a progress report. This will
+          send back an approximate size in the header of each tablespace, which
+          can be used to calculate how far along the stream is done. This is
+          calculated by enumerating all the file sizes once before the transfer
+          is even started, and might as such have a negative impact on the
+          performance.  In particular, it might take longer before the first data
+          is streamed. Since the database files can change during the backup,
+          the size is only approximate and might both grow and shrink between
+          the time of approximation and the sending of the actual files.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>FAST</literal></term>
+        <listitem>
+         <para>
+          Request a fast checkpoint.
+         </para>
+        </listitem>
+       </varlistentry>
+
+       <varlistentry>
+        <term><literal>TABLESPACE_MAP</literal></term>
+        <listitem>
+         <para>
+          Include information about symbolic links present in the directory
+          <filename>pg_tblspc</filename> in a file named
+          <filename>tablespace_map</filename>. The tablespace map file includes
+          each symbolic link name as it exists in the directory
+          <filename>pg_tblspc/</filename> and the full path of that symbolic link.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     
+     <para>
+      In response to this command, server will send out three result sets.
+     </para>
+     <para>
+      The first ordinary result set contains the starting position of the
+      backup, in a single row with two columns. The first column contains
+      the start position given in XLogRecPtr format, and the second column
+      contains the corresponding timeline ID.
+     </para>
+     
+     <para>
+      The second ordinary result set has one row for each tablespace.
+      The fields in this row are:
+      <variablelist>
+       <varlistentry>
+        <term><literal>spcoid</literal> (<type>oid</type>)</term>
+        <listitem>
+         <para>
+          The OID of the tablespace, or null if it's the base
+          directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>spclocation</literal> (<type>text</type>)</term>
+        <listitem>
+         <para>
+          The full path of the tablespace directory, or null
+          if it's the base directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the tablespace, in kilobytes (1024 bytes),
+          if progress report has been requested; otherwise it's null.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+     <para>
+      The final result set will be sent in a single row with two columns. The
+      first column contains the data of <filename>backup_label</filename> file,
+      and the second column contains the data of <filename>tablespace_map</filename>.
+     </para>
+
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>STOP_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>WAL</literal> ]
+        [ <literal>NOWAIT</literal> ]
+
+     <indexterm><primary>STOP_BACKUP</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to finish performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><replaceable class="parameter">LABEL</replaceable><replaceable>'string'</replaceable></term>
+        <listitem>
+         <para>
+          Provides the content of backup_label file to the backup. The content are
+          the same that were returned by <command>START_BACKUP</command>.
+         </para>
+        </listitem>
+       </varlistentry>
+        <varlistentry>
+        <term><literal>WAL</literal></term>
+        <listitem>
+         <para>
+          Include the necessary WAL segments in the backup. This will include
+          all the files between start and stop backup in the
+          <filename>pg_wal</filename> directory of the base directory tar
+          file.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>NOWAIT</literal></term>
+        <listitem>
+         <para>
+          By default, the backup will wait until the last required WAL
+          segment has been archived, or emit a warning if log archiving is
+          not enabled. Specifying <literal>NOWAIT</literal> disables both
+          the waiting and the warning, leaving the client responsible for
+          ensuring the required log is available.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+
+     <para>
+      In response to this command, server will send one or more CopyResponse
+      results followed by a single result set, containing the WAL end position of
+      the backup. The CopyResponse contains <filename>pg_control</filename> and
+      WAL files, if stop backup is run with WAL option.
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_FILE_LIST</literal>
+        <indexterm><primary>SEND_FILE_LIST</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instruct the server to return a list of files and directories, available in
+      data directory. In response to this command, server will send one result set
+      per tablespace. The result sets consist of following fields:
+     </para>
+
+     <variablelist>
+      <varlistentry>
+       <term><literal>path</literal> (<type>text</type>)</term>
+       <listitem>
+        <para>
+         The path and name of the file. In case of tablespace, it is an absolute
+         path on the database server, however, in case of <filename>base</filename>
+         tablespace, it is relative to $PGDATA.
+        </para>
+       </listitem>
+      </varlistentry>
+    
+      <varlistentry>
+       <term><literal>type</literal> (<type>char</type>)</term>
+       <listitem>
+        <para>
+         A single character, identifying the type of file.
+         <itemizedlist spacing="compact" mark="bullet">
+          <listitem>
+           <para>
+            <literal>'f'</literal> - Regular file. Can be any relation or
+            non-relation file in $PGDATA.
+           </para>
+          </listitem>
+    
+          <listitem>
+           <para>
+            <literal>'d'</literal> - Directory.
+           </para>
+          </listitem>
+    
+          <listitem>
+           <para>
+            <literal>'l'</literal> - Symbolic link.
+           </para>
+          </listitem>
+         </itemizedlist>
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the file, in kilobytes (1024 bytes). It's null if
+          type is 'd' or 'l'.
+         </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+       <term><literal>mtime</literal> (<type>Int64</type>)</term>
+        <listitem>
+         <para>
+          The file or directory last modification time, as seconds since the Epoch.
+         </para>
+        </listitem>
+      </varlistentry>
+     </variablelist>
+
+      <para>
+       This list will contain all files and directories in the $PGDATA, regardless of
+       whether they are PostgreSQL files or other files added to the same directory.
+       The only excluded files are:
+       <itemizedlist spacing="compact" mark="bullet">
+        <listitem>
+         <para>
+          <filename>postmaster.pid</filename>
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>postmaster.opts</filename>
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_internal.init</filename> (found in multiple directories)
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Various temporary files and directories created during the operation
+          of the PostgreSQL server, such as any file or directory beginning
+          with <filename>pgsql_tmp</filename> and temporary relations.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Unlogged relations, except for the init fork which is required to
+          recreate the (empty) unlogged relation on recovery.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_wal</filename>, including subdirectories. If the backup is run
+          with WAL files included, a synthesized version of <filename>pg_wal</filename> will be
+          included, but it will only contain the files necessary for the
+          backup to work, not the rest of the contents.
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          <filename>pg_dynshmem</filename>, <filename>pg_notify</filename>,
+          <filename>pg_replslot</filename>, <filename>pg_serial</filename>,
+          <filename>pg_snapshots</filename>, <filename>pg_stat_tmp</filename>, and
+          <filename>pg_subtrans</filename> are copied as empty directories (even if
+          they are symbolic links).
+         </para>
+        </listitem>
+        <listitem>
+         <para>
+          Files other than regular files and directories, such as symbolic
+          links (other than for the directories listed above) and special
+          device files, are skipped.  (Symbolic links
+          in <filename>pg_tblspc</filename> are maintained.)
+         </para>
+        </listitem>
+       </itemizedlist>
+       Owner, group, and file mode are set if the underlying file system on the server
+       supports it.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_FILES ( <replaceable class="parameter">'FILE'</replaceable> [, ...] )</literal>
+        [ <literal>MAX_RATE</literal> <replaceable>rate</replaceable> ]
+        [ <literal>NOVERIFY_CHECKSUMS</literal> ]
+        [ <literal>START_WAL_LOCATION</literal> ]
+
+        <indexterm><primary>SEND_FILES</primary></indexterm>
+    </term>
+
+    <listitem>
+     <para>
+      Instructs the server to send the contents of the requested FILE(s).
+     </para>
+      
+     <para>
+      A clause of the form <literal>SEND_FILES ( 'FILE', 'FILE', ... ) [OPTIONS]</literal>
+      is accepted where one or more FILE(s) can be requested.
+     </para>
+
+     <para>
+      In response to this command, one or more CopyResponse results will be sent,
+      one for each FILE requested. The data in the CopyResponse results will be
+      a tar format (following the “ustar interchange format” specified in the
+      POSIX 1003.1-2008 standard) dump of the tablespace contents, except that
+      the two trailing blocks of zeroes specified in the standard are omitted.
+     </para>
+
+     <para>
+      The following options are accepted:
+       <variablelist>
+        <varlistentry>
+         <term><literal>MAX_RATE</literal> <replaceable>rate</replaceable></term>
+         <listitem>
+          <para>
+           Limit (throttle) the maximum amount of data transferred from server
+           to client per unit of time. The expected unit is kilobytes per second.
+           If this option is specified, the value must either be equal to zero
+           or it must fall within the range from 32 kB through 1 GB (inclusive).
+           If zero is passed or the option is not specified, no restriction is
+           imposed on the transfer.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>NOVERIFY_CHECKSUMS</literal></term>
+         <listitem>
+          <para>
+           By default, checksums are verified during a base backup if they are
+           enabled. Specifying <literal>NOVERIFY_CHECKSUMS</literal> disables
+           this verification.
+          </para>
+         </listitem>
+        </varlistentry>
+
+        <varlistentry>
+         <term><literal>START_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The starting WAL position when START BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+        </varlistentry>
+       </variablelist>
+     </para>
+    </listitem>
+  </varlistentry>
 </variablelist>
 
 </para>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index fc9e222f8d..339e68bda7 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -536,6 +536,26 @@ PostgreSQL documentation
        </para>
       </listitem>
      </varlistentry>
+     
+     <varlistentry>
+      <term><option>-j <replaceable class="parameter">n</replaceable></option></term>
+      <term><option>--jobs=<replaceable class="parameter">n</replaceable></option></term>
+      <listitem>
+       <para>
+        Create <replaceable class="parameter">n</replaceable> threads to copy
+        backup files from the database server. <application>pg_basebackup</application>
+        will open <replaceable class="parameter">n</replaceable> +1 connections
+        to the database. Therefore, the server must be configured with
+        <xref linkend="guc-max-wal-senders"/> set high enough to accommodate all
+        connections.
+       </para>
+       
+       <para>
+        parallel mode only works with plain format.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </para>
 
-- 
2.21.0 (Apple Git-122.2)

0004-Parallel-Backup-Backend-Replication-commands_v7.patchapplication/octet-stream; name=0004-Parallel-Backup-Backend-Replication-commands_v7.patchDownload
From 6ccc7e8970e3ccf9183627692c50a235e05c8c68 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 22:59:28 +0500
Subject: [PATCH 4/7] Parallel Backup - Backend Replication commands

This feature adds four new replication commands to the backend replication
system, to help facilitate taking a full backup in parallel using multiple
connections.

	- START_BACKUP [ LABEL 'label' ] [ PROGRESS ] [ FAST ] [ TABLESPACE_MAP ]
	This command instructs the server to get prepared for performing an
	online backup.

	- STOP_BACKUP [ LABEL 'label' ] [ WAL ] [ NOWAIT ]
	This command instructs the server that online backup is finished. It
	will bring the system out of backup mode.

	- SEND_FILE_LIST
	Instruct the server to return a list of files and directories that
	are available in $PGDATA directory.

	- SEND_FILES ( 'FILE' [, ...] ) [ MAX_RATE rate ] [ NOVERIFY_CHECKSUMS ]
		[ START_WAL_LOCATION ]
	Instructs the server to send the contents of the requested FILE(s).
---
 src/backend/access/transam/xlog.c      |   2 +-
 src/backend/replication/basebackup.c   | 503 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    | 201 ++++++++--
 src/backend/replication/repl_scanner.l |   6 +
 src/include/nodes/replnodes.h          |  10 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 674 insertions(+), 50 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c20dc447f1..f8d9e0655a 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -12288,7 +12288,7 @@ collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index dee590f16a..30d06d72a9 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -38,6 +38,7 @@
 #include "storage/ipc.h"
 #include "storage/reinit.h"
 #include "utils/builtins.h"
+#include "utils/pg_lsn.h"
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
@@ -51,11 +52,20 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	XLogRecPtr	startwallocation;
 } basebackup_options;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	size_t		size;
+	time_t		mtime;
+} BackupFile;
+
 
 static int64 sendDir(const char *path, int basepathlen, bool dryrun,
-					 List *tablespaces, bool sendtblspclinks);
+					 List *tablespaces, bool sendtblspclinks, List **filelist);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -75,6 +85,13 @@ static void throttle(size_t increment);
 static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void StartBackup(basebackup_options *opt);
+static void StopBackup(basebackup_options *opt);
+static void SendFileList(void);
+static void SendFiles(basebackup_options *opt, List *filenames, bool missing_ok);
+static void addToBackupFileList(List **filelist, char *path, char type, size_t size,
+								time_t mtime);
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -289,7 +306,7 @@ perform_base_backup(basebackup_options *opt)
 
 	/* Add a node for the base directory at the end */
 	ti = palloc0(sizeof(tablespaceinfo));
-	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
 	tablespaces = lappend(tablespaces, ti);
 
 	/* Send tablespace header */
@@ -323,10 +340,10 @@ perform_base_backup(basebackup_options *opt)
 			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
 				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-				sendDir(".", 1, false, tablespaces, false);
+				sendDir(".", 1, false, tablespaces, false, NULL);
 			}
 			else
-				sendDir(".", 1, false, tablespaces, true);
+				sendDir(".", 1, false, tablespaces, true, NULL);
 
 			/* ... and pg_control after everything else. */
 			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -337,7 +354,7 @@ perform_base_backup(basebackup_options *opt)
 			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
 		else
-			sendTablespace(ti->path, false);
+			sendTablespace(ti->path, false, NULL);
 
 		/*
 		 * If we're including WAL, and this is the main data directory we
@@ -409,6 +426,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_startwallocation = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -497,12 +515,24 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "start_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *startwallocation;
+
+			if (o_startwallocation)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			startwallocation = strVal(defel->arg);
+			opt->startwallocation = pg_lsn_in_internal(startwallocation, &have_error);
+			o_startwallocation = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
 	}
-	if (opt->label == NULL)
-		opt->label = "base backup";
 }
 
 
@@ -520,6 +550,15 @@ SendBaseBackup(BaseBackupCmd *cmd)
 
 	parse_basebackup_options(cmd->options, &opt);
 
+	/* default value for label, if not specified. */
+	if (opt.label == NULL)
+	{
+		if (cmd->cmdtag == BASE_BACKUP)
+			opt.label = "base backup";
+		else
+			opt.label = "start backup";
+	}
+
 	WalSndSetState(WALSNDSTATE_BACKUP);
 
 	if (update_process_title)
@@ -531,7 +570,29 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			StartBackup(&opt);
+			break;
+		case SEND_FILE_LIST:
+			SendFileList();
+			break;
+		case SEND_FILES:
+			SendFiles(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			StopBackup(&opt);
+			break;
+
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -674,6 +735,61 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_puttextmessage('C', "SELECT");
 }
 
+/*
+ * Send a single resultset containing backup label and tablespace map
+ */
+static void
+SendStartBackupResult(StringInfo labelfile, StringInfo tblspc_map_file)
+{
+	StringInfoData buf;
+	Size		len;
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 2);		/* 2 fields */
+
+	/* Field headers */
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "tablespacemap");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	/* Data row */
+	pq_beginmessage(&buf, 'D');
+	pq_sendint16(&buf, 2);		/* number of columns */
+
+	len = labelfile->len;
+	pq_sendint32(&buf, len);
+	pq_sendbytes(&buf, labelfile->data, len);
+
+	if (tblspc_map_file)
+	{
+		len = tblspc_map_file->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, tblspc_map_file->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* Length = -1 ==> NULL */
+	}
+
+	pq_endmessage(&buf);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -725,7 +841,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool dryrun)
+sendTablespace(char *path, bool dryrun, List **filelist)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -754,11 +870,11 @@ sendTablespace(char *path, bool dryrun)
 		return 0;
 	}
 
+	addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   dryrun);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true, filelist);
 
 	return size;
 }
@@ -777,7 +893,7 @@ sendTablespace(char *path, bool dryrun)
  */
 static int64
 sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
-		bool sendtblspclinks)
+		bool sendtblspclinks, List **filelist)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -931,6 +1047,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
@@ -947,6 +1065,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
@@ -968,6 +1088,10 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									dryrun);
 
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
+			addToBackupFileList(filelist, "./pg_wal/archive_status", 'd', -1,
+								statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -997,6 +1121,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			addToBackupFileList(filelist, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, dryrun);
 #else
@@ -1023,6 +1148,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									dryrun);
+			addToBackupFileList(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1053,13 +1179,15 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks, filelist);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!dryrun)
+			addToBackupFileList(filelist, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!dryrun && filelist == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
@@ -1762,3 +1890,350 @@ setup_throttle(int maxrate)
 		throttling_counter = -1;
 	}
 }
+
+/*
+ * StartBackup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+StartBackup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	labelfile;
+	StringInfo	tblspc_map_file = NULL;
+	int			datadirpathlen;
+	List	   *tablespaces = NIL;
+	tablespaceinfo *ti;
+
+	datadirpathlen = strlen(DataDir);
+
+	backup_started_in_recovery = RecoveryInProgress();
+
+	labelfile = makeStringInfo();
+	tblspc_map_file = makeStringInfo();
+
+	total_checksum_failures = 0;
+
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  labelfile, &tablespaces,
+								  tblspc_map_file,
+								  opt->progress, opt->sendtblspcmapfile);
+
+	/*
+	 * Once do_pg_start_backup has been called, ensure that any failure causes
+	 * us to abort the backup so we don't "leak" a backup counter. For this
+	 * reason, register base_backup_cleanup with before_shmem_exit handler.
+	 * This will make sure that call is always made when process exits. In
+	 * success, do_pg_stop_backup will have taken the system out of backup
+	 * mode and this callback will have no effect, Otherwise the required
+	 * cleanup will be done in any case.
+	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
+
+	SendXlogRecPtrResult(startptr, starttli);
+
+	/*
+	 * Calculate the relative path of temporary statistics directory in order
+	 * to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
+	tablespaces = lappend(tablespaces, ti);
+
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	if ((tblspc_map_file && tblspc_map_file->len <= 0) ||
+		!opt->sendtblspcmapfile)
+		tblspc_map_file = NULL;
+
+	/* send backup_label and tablespace_map to frontend */
+	SendStartBackupResult(labelfile, tblspc_map_file);
+}
+
+/*
+ * StopBackup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */
+static void
+StopBackup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+	struct stat statbuf;
+	StringInfoData buf;
+	char	   *labelfile = NULL;
+
+	if (get_backup_status() != SESSION_BACKUP_NON_EXCLUSIVE)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("non-exclusive backup is not in progress")));
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	/* ... and pg_control after everything else. */
+	if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+		ereport(ERROR,
+				(errcode_for_file_access(),
+				 errmsg("could not stat file \"%s\": %m",
+						XLOG_CONTROL_FILE)));
+	sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
+
+	/* stop backup */
+	labelfile = (char *) opt->label;
+	endptr = do_pg_stop_backup(labelfile, !opt->nowait, &endtli);
+
+	if (opt->includewal)
+		include_wal_files(endptr);
+
+	pq_putemptymessage('c');	/* CopyDone */
+	SendXlogRecPtrResult(endptr, endtli);
+}
+
+/*
+ * SendFileList() - sends a list of filenames to frontend
+ *
+ * The function collects a list of filenames, necessary for a complete backup and
+ * sends this list to the client.
+ */
+static void
+SendFileList(void)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	List	   *tablespaces = NIL;
+	StringInfo	tblspc_map_file = NULL;
+	tablespaceinfo *ti;
+
+	tblspc_map_file = makeStringInfo();
+	collectTablespaces(&tablespaces, tblspc_map_file, false, false);
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	tablespaces = lappend(tablespaces, ti);
+
+	foreach(lc, tablespaces)
+	{
+		List	   *filelist = NULL;
+		tablespaceinfo *ti;
+
+		ti = (tablespaceinfo *) lfirst(lc);
+		if (ti->path == NULL)
+			sendDir(".", 1, true, NIL, true, &filelist);
+		else
+			sendTablespace(ti->path, true, &filelist);
+
+		/* Construct and send the list of filenames */
+		pq_beginmessage(&buf, 'T'); /* RowDescription */
+		pq_sendint16(&buf, 4);	/* n field */
+
+		/* First field - file name */
+		pq_sendstring(&buf, "path");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, TEXTOID);
+		pq_sendint16(&buf, -1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Second field - is_dir */
+		pq_sendstring(&buf, "type");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, CHAROID);
+		pq_sendint16(&buf, 1);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - size */
+		pq_sendstring(&buf, "size");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+
+		/* Third field - mtime */
+		pq_sendstring(&buf, "mtime");
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_sendint32(&buf, INT8OID);
+		pq_sendint16(&buf, 8);
+		pq_sendint32(&buf, 0);
+		pq_sendint16(&buf, 0);
+		pq_endmessage(&buf);
+
+		foreach(lc, filelist)
+		{
+			BackupFile *backupFile = (BackupFile *) lfirst(lc);
+			Size		len;
+
+			/* Send one datarow message */
+			pq_beginmessage(&buf, 'D');
+			pq_sendint16(&buf, 4);	/* number of columns */
+
+			/* send path */
+			len = strlen(backupFile->path);
+			pq_sendint32(&buf, len);
+			pq_sendbytes(&buf, backupFile->path, len);
+
+			/* send type */
+			pq_sendint32(&buf, 1);
+			pq_sendbyte(&buf, backupFile->type);
+
+			/* send size */
+			send_int8_string(&buf, backupFile->size);
+
+			/* send mtime */
+			send_int8_string(&buf, backupFile->mtime);
+
+			pq_endmessage(&buf);
+		}
+
+		if (filelist)
+			pfree(filelist);
+	}
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
+/*
+ * SendFiles() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol. It does only entertains the regular files and any other kind such
+ * as directories or symlink etc will be ignored.
+ */
+static void
+SendFiles(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	int			basepathlen = 1;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Setup and activate network throttling, if client requested it */
+	setup_throttle(opt->maxrate);
+
+	/* set backup start location. */
+	startptr = opt->startwallocation;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (is_absolute_path(pathbuf))
+		{
+			char	   *basepath;
+
+			/*
+			 * 'pathbuf' points to the tablespace location, but we only want
+			 * to include the version directory in it that belongs to us.
+			 */
+			basepath = strstr(pathbuf, TABLESPACE_VERSION_DIRECTORY);
+			if (basepath)
+				basepathlen = basepath - pathbuf - 1;
+		}
+
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/*
+		 * Only entertain requests for regular file, skip any directories or
+		 * special files.
+		 */
+		if (S_ISREG(statbuf.st_mode))
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf, true, InvalidOid);
+		}
+		else
+			ereport(WARNING,
+					(errmsg("skipping special file or directory \"%s\"", pathbuf)));
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report total checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+/*
+ * Construct a BackupFile entry and add to the list.
+ */
+static void
+addToBackupFileList(List **filelist, char *path, char type, size_t size,
+					time_t mtime)
+{
+	BackupFile *backupFile;
+
+	if (filelist)
+	{
+		backupFile = (BackupFile *) palloc0(sizeof(BackupFile));
+		strlcpy(backupFile->path, path, sizeof(backupFile->path));
+		backupFile->type = type;
+		backupFile->size = size;
+		backupFile->mtime = mtime;
+
+		*filelist = lappend(*filelist, backupFile);
+	}
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index c4e11cc4e8..0aa781ebdc 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,13 +87,24 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_SEND_FILE_LIST
+%token K_SEND_FILES
+%token K_STOP_BACKUP
+%token K_START_WAL_LOCATION
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
 				create_replication_slot drop_replication_slot identify_system
 				timeline_history show sql_cmd
 %type <list>	base_backup_opt_list
+				start_backup_opt_list stop_backup_opt_list
+				send_backup_files_opt_list
 %type <defelt>	base_backup_opt
+				backup_opt_label backup_opt_progress backup_opt_maxrate
+				backup_opt_fast backup_opt_tsmap backup_opt_wal backup_opt_nowait
+				backup_opt_chksum backup_opt_wal_loc
+				start_backup_opt stop_backup_opt send_backup_files_opt
 %type <uintval>	opt_timeline
 %type <list>	plugin_options plugin_opt_list
 %type <defelt>	plugin_opt_elem
@@ -102,6 +113,7 @@ static SQLCmd *make_sqlcmd(void);
 %type <boolval>	opt_temporary
 %type <list>	create_slot_opt_list
 %type <defelt>	create_slot_opt
+%type <list>	backup_files backup_files_list
 
 %%
 
@@ -162,10 +174,61 @@ base_backup:
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_START_BACKUP start_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILE_LIST
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = NIL;
+					cmd->cmdtag = SEND_FILE_LIST;
+					$$ = (Node *) cmd;
+				}
+			| K_SEND_FILES backup_files send_backup_files_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_FILES;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
+				}
+			| K_STOP_BACKUP stop_backup_opt_list
+				{
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
 					$$ = (Node *) cmd;
 				}
 			;
 
+start_backup_opt_list:
+	start_backup_opt_list start_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+			;
+
+stop_backup_opt_list:
+	stop_backup_opt_list stop_backup_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
+send_backup_files_opt_list:
+	send_backup_files_opt_list send_backup_files_opt
+		{ $$ = lappend($1, $2); }
+	| /* EMPTY */
+		{ $$ = NIL; }
+	;
+
 base_backup_opt_list:
 			base_backup_opt_list base_backup_opt
 				{ $$ = lappend($1, $2); }
@@ -173,46 +236,116 @@ base_backup_opt_list:
 				{ $$ = NIL; }
 			;
 
+start_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_progress	{ $$ = $1; }
+		| backup_opt_fast		{ $$ = $1; }
+		| backup_opt_tsmap		{ $$ = $1; }
+			;
+
+stop_backup_opt:
+		backup_opt_label		{ $$ = $1; }
+		| backup_opt_wal 		{ $$ = $1; }
+		| backup_opt_nowait		{ $$ = $1; }
+			;
+
+send_backup_files_opt:
+			backup_opt_maxrate		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_wal_loc	{ $$ = $1; }
+			;
+
 base_backup_opt:
-			K_LABEL SCONST
-				{
-				  $$ = makeDefElem("label",
-								   (Node *)makeString($2), -1);
-				}
-			| K_PROGRESS
-				{
-				  $$ = makeDefElem("progress",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_FAST
-				{
-				  $$ = makeDefElem("fast",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_WAL
-				{
-				  $$ = makeDefElem("wal",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_NOWAIT
-				{
-				  $$ = makeDefElem("nowait",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_MAX_RATE UCONST
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_progress	{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			| backup_opt_wal 		{ $$ = $1; }
+			| backup_opt_nowait		{ $$ = $1; }
+			| backup_opt_maxrate	{ $$ = $1; }
+			| backup_opt_tsmap		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			;
+
+backup_opt_label:
+	K_LABEL SCONST
+	{
+	  $$ = makeDefElem("label",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_progress:
+	K_PROGRESS
+	{
+	  $$ = makeDefElem("progress",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_fast:
+	K_FAST
+	{
+	  $$ = makeDefElem("fast",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal:
+	K_WAL
+	{
+	  $$ = makeDefElem("wal",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_nowait:
+	K_NOWAIT
+	{
+	  $$ = makeDefElem("nowait",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_maxrate:
+	K_MAX_RATE UCONST
+	{
+	  $$ = makeDefElem("max_rate",
+					   (Node *)makeInteger($2), -1);
+	};
+
+backup_opt_tsmap:
+	K_TABLESPACE_MAP
+	{
+	  $$ = makeDefElem("tablespace_map",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_chksum:
+	K_NOVERIFY_CHECKSUMS
+	{
+	  $$ = makeDefElem("noverify_checksums",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal_loc:
+	K_START_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("start_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_files:
+			'(' backup_files_list ')'
 				{
-				  $$ = makeDefElem("max_rate",
-								   (Node *)makeInteger($2), -1);
+					$$ = $2;
 				}
-			| K_TABLESPACE_MAP
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			SCONST
 				{
-				  $$ = makeDefElem("tablespace_map",
-								   (Node *)makeInteger(true), -1);
+					$$ = list_make1(makeString($1));
 				}
-			| K_NOVERIFY_CHECKSUMS
+			| backup_files_list ',' SCONST
 				{
-				  $$ = makeDefElem("noverify_checksums",
-								   (Node *)makeInteger(true), -1);
+					$$ = lappend($1, makeString($3));
 				}
 			;
 
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 380faeb5f6..d2e2dfe1e9 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,12 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+SEND_FILE_LIST		{ return K_SEND_FILE_LIST; }
+SEND_FILES			{ return K_SEND_FILES; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
+
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 1e3ed4e19f..eac4802c7e 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,14 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	SEND_FILE_LIST,
+	SEND_FILES,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +50,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index b55917b9b6..5202e4160b 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool dryrun);
+extern int64 sendTablespace(char *path, bool dryrun, List **filelist);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122.2)

0003-Refactor-some-basebackup-code-to-increase-reusabilit_v7.patchapplication/octet-stream; name=0003-Refactor-some-basebackup-code-to-increase-reusabilit_v7.patchDownload
From 896fbef37a1feec87b770ea16514ce2b319adb39 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 9 Oct 2019 12:39:41 +0500
Subject: [PATCH 3/7] Refactor some basebackup code to increase reusability.
 This commit adds a new function collectTablespaces and have moved the code
 that collects tablespace information from do_pg_start_backup to it.

This does not introduce any functional change.
---
 src/backend/access/transam/xlog.c    | 192 +++++-----
 src/backend/replication/basebackup.c | 510 ++++++++++++++-------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 369 insertions(+), 335 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6bc1a6b46d..c20dc447f1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10309,10 +10309,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10438,93 +10434,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collectTablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12300,3 +12210,103 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+				   bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to
+		 * ensure that we can distinguish between the newline in the
+		 * tablespace path and end of line while reading tablespace_map
+		 * file during archive recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory
+		 * when it's located within PGDATA, or NULL if it's located
+		 * elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created
+		 * them. Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 5774117089..dee590f16a 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -67,10 +67,12 @@ static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
 static void perform_base_backup(basebackup_options *opt);
+static void include_wal_files(XLogRecPtr endptr);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
+static void setup_throttle(int maxrate);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
 /* Was the backup currently in-progress initiated in recovery mode? */
@@ -293,29 +295,7 @@ perform_base_backup(basebackup_options *opt)
 	/* Send tablespace header */
 	SendBackupHeader(tablespaces);
 
-	/* Setup and activate network throttling, if client requested it */
-	if (opt->maxrate > 0)
-	{
-		throttling_sample =
-			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
-
-		/*
-		 * The minimum amount of time for throttling_sample bytes to be
-		 * transferred.
-		 */
-		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-		/* Enable throttling. */
-		throttling_counter = 0;
-
-		/* The 'real data' starts now (header was ignored). */
-		throttled_last = GetCurrentTimestamp();
-	}
-	else
-	{
-		/* Disable throttling. */
-		throttling_counter = -1;
-	}
+	setup_throttle(opt->maxrate);
 
 	/* Send off our tablespaces one by one */
 	foreach(lc, tablespaces)
@@ -381,227 +361,7 @@ perform_base_backup(basebackup_options *opt)
 		 * We've left the last tar file "open", so we can now append the
 		 * required WAL files to it.
 		 */
-		char		pathbuf[MAXPGPATH];
-		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
-		struct stat statbuf;
-		List	   *historyFileList = NIL;
-		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
-		ListCell   *lc;
-		TimeLineID	tli;
-
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
-		/* Ok, we have everything we need. Send the WAL files. */
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			FILE	   *fp;
-			char		buf[TAR_SEND_SIZE];
-			size_t		cnt;
-			pgoff_t		len = 0;
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-
-			fp = AllocateFile(pathbuf, "rb");
-			if (fp == NULL)
-			{
-				int			save_errno = errno;
-
-				/*
-				 * Most likely reason for this is that the file was already
-				 * removed by a checkpoint, so check for that to get a better
-				 * error message.
-				 */
-				CheckXLogRemoved(segno, tli);
-
-				errno = save_errno;
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not open file \"%s\": %m", pathbuf)));
-			}
-
-			if (fstat(fileno(fp), &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m",
-								pathbuf)));
-			if (statbuf.st_size != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* send the WAL file itself */
-			_tarWriteHeader(pathbuf, NULL, &statbuf, false);
-
-			while ((cnt = fread(buf, 1,
-								Min(sizeof(buf), wal_segment_size - len),
-								fp)) > 0)
-			{
-				CheckXLogRemoved(segno, tli);
-				/* Send the chunk as a CopyData message */
-				if (pq_putmessage('d', buf, cnt))
-					ereport(ERROR,
-							(errmsg("base backup could not send data, aborting backup")));
-
-				len += cnt;
-				throttle(cnt);
-
-				if (len == wal_segment_size)
-					break;
-			}
-
-			CHECK_FREAD_ERROR(fp, pathbuf);
-
-			if (len != wal_segment_size)
-			{
-				CheckXLogRemoved(segno, tli);
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("unexpected WAL file size \"%s\"", walFileName)));
-			}
-
-			/* wal_segment_size is a multiple of 512, so no need for padding */
-
-			FreeFile(fp);
-
-			/*
-			 * Mark file as archived, otherwise files can get archived again
-			 * after promotion of a new node. This is in line with
-			 * walreceiver.c always doing an XLogArchiveForceDone() after a
-			 * complete segment.
-			 */
-			StatusFilePath(pathbuf, walFileName, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
-
-		/*
-		 * Send timeline history files too. Only the latest timeline history
-		 * file is required for recovery, and even that only if there happens
-		 * to be a timeline switch in the first WAL segment that contains the
-		 * checkpoint record, or if we're taking a base backup from a standby
-		 * server and the target timeline changes while the backup is taken.
-		 * But they are small and highly useful for debugging purposes, so
-		 * better include them all, always.
-		 */
-		foreach(lc, historyFileList)
-		{
-			char	   *fname = lfirst(lc);
-
-			snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
-
-			if (lstat(pathbuf, &statbuf) != 0)
-				ereport(ERROR,
-						(errcode_for_file_access(),
-						 errmsg("could not stat file \"%s\": %m", pathbuf)));
-
-			sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
-
-			/* unconditionally mark file as archived */
-			StatusFilePath(pathbuf, fname, ".done");
-			sendFileWithContent(pathbuf, "");
-		}
+		include_wal_files(endptr);
 
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
@@ -1740,3 +1500,265 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * Append the required WAL files to the backup tar file. It assumes that the
+ * last tar file is "open" and the WALs will be appended to it.
+ */
+static void
+include_wal_files(XLogRecPtr endptr)
+{
+	/*
+	 * We've left the last tar file "open", so we can now append the required
+	 * WAL files to it.
+	 */
+	char		pathbuf[MAXPGPATH];
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	struct stat statbuf;
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and include
+	 * all WAL files in the range between 'startptr' and 'endptr', regardless
+	 * of the timeline the file is stamped with. If there are some spurious
+	 * WAL files belonging to timelines that don't belong in this server's
+	 * history, they will be included too. Normally there shouldn't be such
+	 * files, but if there are, there's little harm in including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			historyFileList = lappend(historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we need
+	 * were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from oldest
+	 * to newest, to reduce the chance that a file is recycled before we get a
+	 * chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since we
+	 * are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	/* Ok, we have everything we need. Send the WAL files. */
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		FILE	   *fp;
+		char		buf[TAR_SEND_SIZE];
+		size_t		cnt;
+		pgoff_t		len = 0;
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+
+		fp = AllocateFile(pathbuf, "rb");
+		if (fp == NULL)
+		{
+			int			save_errno = errno;
+
+			/*
+			 * Most likely reason for this is that the file was already
+			 * removed by a checkpoint, so check for that to get a better
+			 * error message.
+			 */
+			CheckXLogRemoved(segno, tli);
+
+			errno = save_errno;
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not open file \"%s\": %m", pathbuf)));
+		}
+
+		if (fstat(fileno(fp), &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m",
+							pathbuf)));
+		if (statbuf.st_size != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* send the WAL file itself */
+		_tarWriteHeader(pathbuf, NULL, &statbuf, false);
+
+		while ((cnt = fread(buf, 1,
+							Min(sizeof(buf), wal_segment_size - len),
+							fp)) > 0)
+		{
+			CheckXLogRemoved(segno, tli);
+			/* Send the chunk as a CopyData message */
+			if (pq_putmessage('d', buf, cnt))
+				ereport(ERROR,
+						(errmsg("base backup could not send data, aborting backup")));
+
+			len += cnt;
+			throttle(cnt);
+
+			if (len == wal_segment_size)
+				break;
+		}
+
+		CHECK_FREAD_ERROR(fp, pathbuf);
+
+		if (len != wal_segment_size)
+		{
+			CheckXLogRemoved(segno, tli);
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("unexpected WAL file size \"%s\"", walFileName)));
+		}
+
+		/* wal_segment_size is a multiple of 512, so no need for padding */
+
+		FreeFile(fp);
+
+		/*
+		 * Mark file as archived, otherwise files can get archived again after
+		 * promotion of a new node. This is in line with walreceiver.c always
+		 * doing an XLogArchiveForceDone() after a complete segment.
+		 */
+		StatusFilePath(pathbuf, walFileName, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+
+	/*
+	 * Send timeline history files too. Only the latest timeline history file
+	 * is required for recovery, and even that only if there happens to be a
+	 * timeline switch in the first WAL segment that contains the checkpoint
+	 * record, or if we're taking a base backup from a standby server and the
+	 * target timeline changes while the backup is taken. But they are small
+	 * and highly useful for debugging purposes, so better include them all,
+	 * always.
+	 */
+	foreach(lc, historyFileList)
+	{
+		char	   *fname = lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", fname);
+
+		if (lstat(pathbuf, &statbuf) != 0)
+			ereport(ERROR,
+					(errcode_for_file_access(),
+					 errmsg("could not stat file \"%s\": %m", pathbuf)));
+
+		sendFile(pathbuf, pathbuf, &statbuf, false, InvalidOid);
+
+		/* unconditionally mark file as archived */
+		StatusFilePath(pathbuf, fname, ".done");
+		sendFileWithContent(pathbuf, "");
+	}
+}
+
+/*
+ * Setup and activate network throttling, if client requested it
+ */
+static void
+setup_throttle(int maxrate)
+{
+	if (maxrate > 0)
+	{
+		throttling_sample =
+			(int64) maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
+
+		/* Enable throttling. */
+		throttling_counter = 0;
+
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
+}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 9b588c87a5..6d27ab9444 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -349,6 +349,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 									 bool needtblspcmapfile);
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
+extern void collectTablespaces(List **tablespaces, StringInfo tblspcmapfile,
+							   bool infotbssize, bool needtblspcmapfile);
 extern void do_pg_abort_backup(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.0 (Apple Git-122.2)

0006-parallel-backup-testcase_v7.patchapplication/octet-stream; name=0006-parallel-backup-testcase_v7.patchDownload
From 7e1c4c88a1f6ac6c323fee035569fa3f246a3972 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 6/7] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 527 ++++++++++++++++++
 1 file changed, 527 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..4ec4c1e0f6
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,527 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 95;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+#	# Create a temporary directory in the system location and symlink it
+#	# to our physical temp location.  That way we can use shorter names
+#	# for the tablespace directories, which hopefully won't run afoul of
+#	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+my $file;
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.0 (Apple Git-122.2)

0005-Parallel-Backup-pg_basebackup_v7.patchapplication/octet-stream; name=0005-Parallel-Backup-pg_basebackup_v7.patchDownload
From bcfe471e924a88cffda223577335ca0c878a3c9c Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 14 Oct 2019 17:28:58 +0500
Subject: [PATCH 5/7] Parallel Backup - pg_basebackup

Implements the replication commands added in the backend replication
system and adds support for --jobs=NUM in pg_basebackup to take a full
backup in parallel using multiple connections. The utility will collect
a list of files from the server first and then workers will copy files
(one by one) over COPY protocol.
---
 src/bin/pg_basebackup/pg_basebackup.c | 766 ++++++++++++++++++++++++--
 1 file changed, 735 insertions(+), 31 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 16886fbe71..c8a36a0c12 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -13,6 +13,7 @@
 
 #include "postgres_fe.h"
 
+#include <pthread.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <sys/stat.h>
@@ -85,12 +86,65 @@ typedef struct UnpackTarState
 	const char *mapped_tblspc_path;
 	pgoff_t		current_len_left;
 	int			current_padding;
+	size_t		current_bytes_read;
 	FILE	   *file;
 } UnpackTarState;
 
 typedef void (*WriteDataCallback) (size_t nbytes, char *buf,
 								   void *callback_data);
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+
+	int			tsIndex;		/* index of tsInfo this file belongs to. */
+} BackupFile;
+
+typedef struct
+{
+	Oid			tblspcOid;
+	char	   *tablespace;		/* tablespace name or NULL if 'base'
+								 * tablespace */
+	int			numFiles;		/* number of files */
+	BackupFile *backupFiles;	/* list of files in a tablespace */
+} TablespaceInfo;
+
+typedef struct
+{
+	int			tablespacecount;
+	int			totalfiles;
+	int			numWorkers;
+
+	char		xlogstart[64];
+	char	   *backup_label;
+	char	   *tablespace_map;
+
+	TablespaceInfo *tsInfo;
+	BackupFile **files;			/* list of BackupFile pointers */
+	int			fileIndex;		/* index of file to be fetched */
+
+	PGconn	  **workerConns;
+} BackupInfo;
+
+typedef struct
+{
+	BackupInfo *backupInfo;
+	uint64		bytesRead;
+
+	int			workerid;
+	pthread_t	worker;
+
+	bool		terminated;
+} WorkerState;
+
+BackupInfo *backupInfo = NULL;
+WorkerState *workers = NULL;
+
+static pthread_mutex_t fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -144,6 +198,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -174,10 +231,11 @@ static PQExpBuffer recoveryconfcontents = NULL;
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
+static void workers_progress_report(uint64 totalBytesRead, const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveTarCopyChunk(size_t r, char *copybuf, void *callback_data);
-static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
+static int	ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf,
 										 void *callback_data);
 static void BaseBackup(void);
@@ -188,6 +246,18 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void ParallelBackupRun(BackupInfo *backupInfo);
+static void StopBackup(BackupInfo *backupInfo);
+static void GetBackupFileList(PGconn *conn, BackupInfo *backupInfo);
+static int	GetBackupFile(WorkerState *wstate);
+static BackupFile *getNextFile(BackupInfo *backupInfo);
+static int	compareFileSize(const void *a, const void *b);
+static void read_label_tblspcmap(PGconn *conn, char **backup_label, char **tablespace_map);
+static void create_backup_dirs(bool basetablespace, char *tablespace, char *name);
+static void create_tblspc_symlink(char *filename);
+static void writefile(char *path, char *buf);
+static void *workerRun(void *arg);
+
 
 static void
 cleanup_directories_atexit(void)
@@ -239,6 +309,18 @@ cleanup_directories_atexit(void)
 static void
 disconnect_atexit(void)
 {
+	/* close worker connections */
+	if (backupInfo && backupInfo->workerConns != NULL)
+	{
+		int			i;
+
+		for (i = 0; i < numWorkers; i++)
+		{
+			if (backupInfo->workerConns[i] != NULL)
+				PQfinish(backupInfo->workerConns[i]);
+		}
+	}
+
 	if (conn != NULL)
 		PQfinish(conn);
 }
@@ -386,6 +468,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -732,6 +815,94 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 	}
 }
 
+/*
+ * Print a progress report of worker threads. If verbose output
+ * is enabled, also print the current file name.
+ *
+ * Progress report is written at maximum once per second, unless the
+ * force parameter is set to true.
+ */
+static void
+workers_progress_report(uint64 totalBytesRead, const char *filename, bool force)
+{
+	int			percent;
+	char		totalBytesRead_str[32];
+	char		totalsize_str[32];
+	pg_time_t	now;
+
+	if (!showprogress)
+		return;
+
+	now = time(NULL);
+	if (now == last_progress_report && !force)
+		return;					/* Max once per second */
+
+	last_progress_report = now;
+	percent = totalsize_kb ? (int) ((totalBytesRead / 1024) * 100 / totalsize_kb) : 0;
+
+	/*
+	 * Avoid overflowing past 100% or the full size. This may make the total
+	 * size number change as we approach the end of the backup (the estimate
+	 * will always be wrong if WAL is included), but that's better than having
+	 * the done column be bigger than the total.
+	 */
+	if (percent > 100)
+		percent = 100;
+	if (totalBytesRead / 1024 > totalsize_kb)
+		totalsize_kb = totalBytesRead / 1024;
+
+	/*
+	 * Separate step to keep platform-dependent format code out of
+	 * translatable strings.  And we only test for INT64_FORMAT availability
+	 * in snprintf, not fprintf.
+	 */
+	snprintf(totalBytesRead_str, sizeof(totalBytesRead_str), INT64_FORMAT,
+			 totalBytesRead / 1024);
+	snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
+
+#define VERBOSE_FILENAME_LENGTH 35
+
+	if (verbose)
+	{
+		if (!filename)
+
+			/*
+			 * No filename given, so clear the status line (used for last
+			 * call)
+			 */
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied %*s"),
+					(int) strlen(totalsize_str),
+					totalBytesRead_str, totalsize_str,
+					percent,
+					VERBOSE_FILENAME_LENGTH + 5, "");
+		else
+		{
+			bool		truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
+
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied, current file (%s%-*.*s)"),
+					(int) strlen(totalsize_str), totalBytesRead_str, totalsize_str,
+					percent,
+			/* Prefix with "..." if we do leading truncation */
+					truncate ? "..." : "",
+					truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+					truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+			/* Truncate filename at beginning if it's too long */
+					truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+				(int) strlen(totalsize_str),
+				totalBytesRead_str, totalsize_str,
+				percent);
+	}
+
+	if (isatty(fileno(stderr)))
+		fprintf(stderr, "\r");
+	else
+		fprintf(stderr, "\n");
+}
 
 /*
  * Print a progress report based on the global variables. If verbose output
@@ -748,7 +919,7 @@ progress_report(int tablespacenum, const char *filename, bool force)
 	char		totalsize_str[32];
 	pg_time_t	now;
 
-	if (!showprogress)
+	if (!showprogress || numWorkers > 1)
 		return;
 
 	now = time(NULL);
@@ -1409,8 +1580,10 @@ get_tablespace_mapping(const char *dir)
 	canonicalize_path(canon_dir);
 
 	for (cell = tablespace_dirs.head; cell; cell = cell->next)
+	{
 		if (strcmp(canon_dir, cell->old_dir) == 0)
 			return cell->new_dir;
+	}
 
 	return dir;
 }
@@ -1425,7 +1598,7 @@ get_tablespace_mapping(const char *dir)
  * specified directory. If it's for another tablespace, it will be restored
  * in the original or mapped directory.
  */
-static void
+static int
 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 {
 	UnpackTarState state;
@@ -1456,13 +1629,12 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 		exit(1);
 	}
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
-
 	/*
 	 * No data is synced here, everything is done for all tablespaces at the
 	 * end.
 	 */
+
+	return state.current_bytes_read;
 }
 
 static void
@@ -1485,6 +1657,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			exit(1);
 		}
 		totaldone += 512;
+		state->current_bytes_read += 512;
 
 		state->current_len_left = read_tar_number(&copybuf[124], 12);
 
@@ -1616,6 +1789,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			fclose(state->file);
 			state->file = NULL;
 			totaldone += r;
+			state->current_bytes_read += r;
 			return;
 		}
 
@@ -1625,6 +1799,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			exit(1);
 		}
 		totaldone += r;
+		state->current_bytes_read += r;
 		progress_report(state->tablespacenum, state->filename, false);
 
 		state->current_len_left -= r;
@@ -1724,16 +1899,28 @@ BaseBackup(void)
 			fprintf(stderr, "\n");
 	}
 
-	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
-				 escaped_label,
-				 showprogress ? "PROGRESS" : "",
-				 includewal == FETCH_WAL ? "WAL" : "",
-				 fastcheckpoint ? "FAST" : "",
-				 includewal == NO_WAL ? "" : "NOWAIT",
-				 maxrate_clause ? maxrate_clause : "",
-				 format == 't' ? "TABLESPACE_MAP" : "",
-				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	if (numWorkers <= 1)
+	{
+		basebkp =
+			psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 includewal == FETCH_WAL ? "WAL" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 includewal == NO_WAL ? "" : "NOWAIT",
+					 maxrate_clause ? maxrate_clause : "",
+					 format == 't' ? "TABLESPACE_MAP" : "",
+					 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	}
+	else
+	{
+		basebkp =
+			psprintf("START_BACKUP LABEL '%s' %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 format == 't' ? "TABLESPACE_MAP" : "");
+	}
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
@@ -1783,7 +1970,7 @@ BaseBackup(void)
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1839,24 +2026,75 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
+	if (numWorkers > 1)
 	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
+		int			j = 0,
+					k = 0;
 
-	if (showprogress)
+		backupInfo = palloc0(sizeof(BackupInfo));
+		backupInfo->workerConns = (PGconn **) palloc0(sizeof(PGconn *) * numWorkers);
+		backupInfo->tablespacecount = tablespacecount;
+		backupInfo->numWorkers = numWorkers;
+		strlcpy(backupInfo->xlogstart, xlogstart, sizeof(backupInfo->xlogstart));
+
+		read_label_tblspcmap(conn, &backupInfo->backup_label, &backupInfo->tablespace_map);
+
+		/* retrieve backup file list from the server. */
+		GetBackupFileList(conn, backupInfo);
+
+		/*
+		 * add backup_label in backup, (for tar format, ReceiveTarFile() will
+		 * take care of it).
+		 */
+		if (format == 'p')
+			writefile("backup_label", backupInfo->backup_label);
+
+		/*
+		 * Flatten the file list to avoid unnecessary locks and enable the
+		 * sequential access to file list. (Creating an array of BackupFile
+		 * structre pointers).
+		 */
+		backupInfo->files =
+			(BackupFile **) palloc0(sizeof(BackupFile *) * backupInfo->totalfiles);
+		for (i = 0; i < backupInfo->tablespacecount; i++)
+		{
+			TablespaceInfo *curTsInfo = &backupInfo->tsInfo[i];
+
+			for (j = 0; j < curTsInfo->numFiles; j++)
+			{
+				backupInfo->files[k] = &curTsInfo->backupFiles[j];
+				k++;
+			}
+		}
+
+		ParallelBackupRun(backupInfo);
+		StopBackup(backupInfo);
+	}
+	else
 	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
+
+		if (showprogress)
+		{
+			progress_report(PQntuples(tablespacehdr), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
 	}
 
+	/* Write recovery contents */
+	if (format == 'p' && writerecoveryconf)
+		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
+
 	PQclear(res);
 
 	/*
@@ -2052,6 +2290,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2079,7 +2318,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2220,6 +2459,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2334,6 +2576,22 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (format != 'p' && numWorkers > 1)
+	{
+		pg_log_error("parallel jobs are only supported with 'plain' format");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2406,3 +2664,449 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+/*
+ * Thread worker
+ */
+static void *
+workerRun(void *arg)
+{
+	WorkerState *wstate = (WorkerState *) arg;
+
+	GetBackupFile(wstate);
+
+	wstate->terminated = true;
+	return NULL;
+}
+
+/*
+ * Runs the worker threads and updates progress until all workers have
+ * terminated/completed.
+ */
+static void
+ParallelBackupRun(BackupInfo *backupInfo)
+{
+	int			status,
+				i;
+	bool		threadsActive = true;
+	uint64		totalBytes = 0;
+
+	workers = (WorkerState *) palloc0(sizeof(WorkerState) * numWorkers);
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		WorkerState *worker = &workers[i];
+
+		worker->backupInfo = backupInfo;
+		worker->workerid = i;
+		worker->bytesRead = 0;
+		worker->terminated = false;
+
+		backupInfo->workerConns[i] = GetConnection();
+		status = pthread_create(&worker->worker, NULL, workerRun, worker);
+		if (status != 0)
+		{
+			pg_log_error("failed to create thread: %m");
+			exit(1);
+		}
+
+		if (verbose)
+			pg_log_info("backup worker (%d) created, %d", i, status);
+	}
+
+	/*
+	 * This is the main thread for updating progress. It waits for workers to
+	 * complete and gets updated status during every loop iteration.
+	 */
+	while (threadsActive)
+	{
+		char	   *filename = NULL;
+
+		threadsActive = false;
+		totalBytes = 0;
+
+		for (i = 0; i < numWorkers; i++)
+		{
+			WorkerState *worker = &workers[i];
+
+			totalBytes += worker->bytesRead;
+			threadsActive |= !worker->terminated;
+		}
+
+		if (backupInfo->fileIndex < backupInfo->totalfiles)
+			filename = backupInfo->files[backupInfo->fileIndex]->path;
+
+		workers_progress_report(totalBytes, filename, false);
+		pg_usleep(100000);
+	}
+
+	if (showprogress)
+	{
+		workers_progress_report(totalBytes, NULL, true);
+		if (isatty(fileno(stderr)))
+			fprintf(stderr, "\n");	/* Need to move to next line */
+	}
+}
+
+/*
+ * Take the system out of backup mode.
+ */
+static void
+StopBackup(BackupInfo *backupInfo)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP LABEL '%s' %s %s",
+					   backupInfo->backup_label,
+					   includewal == FETCH_WAL ? "WAL" : "",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/* receive pg_control and wal files */
+	ReceiveAndUnpackTarFile(conn, res, tablespacecount);
+	PQclear(res);
+}
+
+/*
+ * Retrieve backup file list from the server and populate TablespaceInfo struct
+ * to keep track of tablespaces and its files.
+ */
+static void
+GetBackupFileList(PGconn *conn, BackupInfo *backupInfo)
+{
+	TablespaceInfo *tsInfo;
+	PGresult   *res = NULL;
+	char	   *basebkp;
+	int			i;
+
+	backupInfo->tsInfo = palloc0(sizeof(TablespaceInfo) * backupInfo->tablespacecount);
+	tsInfo = backupInfo->tsInfo;
+
+	/*
+	 * Get list of files.
+	 */
+	basebkp = psprintf("SEND_FILE_LIST");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SEND_FILE_LIST", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * The list of files is grouped by tablespaces, and we want to fetch them
+	 * in the same order.
+	 */
+	for (i = 0; i < backupInfo->tablespacecount; i++)
+	{
+		bool		basetablespace;
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get backup header: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tsInfo[i].tblspcOid = atol(PQgetvalue(tablespacehdr, i, 0));
+		tsInfo[i].tablespace = PQgetvalue(tablespacehdr, i, 1);
+		tsInfo[i].numFiles = PQntuples(res);
+		tsInfo[i].backupFiles = palloc0(sizeof(BackupFile) * tsInfo[i].numFiles);
+
+		/* keep count of all files in backup */
+		backupInfo->totalfiles += tsInfo[i].numFiles;
+
+		for (int j = 0; j < tsInfo[i].numFiles; j++)
+		{
+			char	   *path = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+			{
+				create_backup_dirs(basetablespace, tsInfo[i].tablespace, path);
+				continue;
+			}
+
+			if (format == 'p' && type == 'l')
+			{
+				create_tblspc_symlink(path);
+				continue;
+			}
+
+			strlcpy(tsInfo[i].backupFiles[j].path, path, MAXPGPATH);
+			tsInfo[i].backupFiles[j].type = type;
+			tsInfo[i].backupFiles[j].size = size;
+			tsInfo[i].backupFiles[j].mtime = mtime;
+			tsInfo[i].backupFiles[j].tsIndex = i;
+		}
+
+		/* sort files in descending order, based on size */
+		qsort(tsInfo[i].backupFiles, tsInfo[i].numFiles,
+			  sizeof(BackupFile), &compareFileSize);
+		PQclear(res);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+}
+
+/*
+ * Retrieve and write backup file from the server. The file list is provided by
+ * worker state. It pulls a single file from this list and writes it to the
+ * backup directory.
+ */
+static int
+GetBackupFile(WorkerState *wstate)
+{
+	PGresult   *res = NULL;
+	PGconn	   *worker_conn = NULL;
+	BackupFile *fetchFile = NULL;
+	BackupInfo *backupInfo = NULL;
+
+	backupInfo = wstate->backupInfo;
+	worker_conn = backupInfo->workerConns[wstate->workerid];
+	while ((fetchFile = getNextFile(backupInfo)) != NULL)
+	{
+		PQExpBuffer buf = createPQExpBuffer();
+
+		/*
+		 * Fetch a single file from the server. To fetch the file, build a
+		 * query in form of:
+		 *
+		 * SEND_FILES ('base/1/1245/32683') [options]
+		 */
+		appendPQExpBuffer(buf, "SEND_FILES ( '%s' )", fetchFile->path);
+
+		/* add options */
+		appendPQExpBuffer(buf, " START_WAL_LOCATION '%s' %s %s",
+						  backupInfo->xlogstart,
+						  format == 't' ? "TABLESPACE_MAP" : "",
+						  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+		if (maxrate > 0)
+			appendPQExpBuffer(buf, " MAX_RATE %u", maxrate);
+
+		if (!worker_conn)
+			return 1;
+
+		if (PQsendQuery(worker_conn, buf->data) == 0)
+		{
+			pg_log_error("could not send files list \"%s\"",
+						 PQerrorMessage(worker_conn));
+			return 1;
+		}
+
+		destroyPQExpBuffer(buf);
+
+		/* process file contents, also count bytesRead for progress */
+		wstate->bytesRead +=
+			ReceiveAndUnpackTarFile(worker_conn, tablespacehdr, fetchFile->tsIndex);
+
+		res = PQgetResult(worker_conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data stream: %s",
+						 PQerrorMessage(worker_conn));
+			exit(1);
+		}
+
+		res = PQgetResult(worker_conn);
+	}
+
+	PQclear(res);
+	return 0;
+}
+
+/*
+ * Increment fileIndex and store it in a local variable so that even a
+ * context switch does not affect the file index value and we don't accidentally
+ * increment the value twice and therefore skip some files.
+ */
+static BackupFile *
+getNextFile(BackupInfo *backupInfo)
+{
+	int			fileIndex = 0;
+
+	pthread_mutex_lock(&fetch_mutex);
+	fileIndex = backupInfo->fileIndex++;
+	pthread_mutex_unlock(&fetch_mutex);
+
+	if (fileIndex >= backupInfo->totalfiles)
+		return NULL;
+
+	return backupInfo->files[fileIndex];
+}
+
+/* qsort comparator for BackupFile (sort descending order)  */
+static int
+compareFileSize(const void *a, const void *b)
+{
+	const BackupFile *v1 = (BackupFile *) a;
+	const BackupFile *v2 = (BackupFile *) b;
+
+	if (v1->size > v2->size)
+		return -1;
+	if (v1->size < v2->size)
+		return 1;
+
+	return 0;
+}
+
+static void
+read_label_tblspcmap(PGconn *conn, char **backuplabel, char **tblspc_map)
+{
+	PGresult   *res = NULL;
+
+	Assert(backuplabel != NULL);
+	Assert(tblspc_map != NULL);
+
+	/*
+	 * Get Backup label and tablespace map data.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) < 1)
+	{
+		pg_log_error("no data returned from server");
+		exit(1);
+	}
+
+	*backuplabel = PQgetvalue(res, 0, 0);	/* backup_label */
+	if (!PQgetisnull(res, 0, 1))
+		*tblspc_map = PQgetvalue(res, 0, 1);	/* tablespace_map */
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	PQclear(res);
+}
+
+/*
+ * Create backup directories while taking care of tablespace path. If tablespace
+ * mapping (with -T) is given then the directory will be created on the mapped
+ * path.
+ */
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char		dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+/*
+ * Create a symlink in pg_tblspc and apply any tablespace mapping given on
+ * the command line (--tablespace-mapping).
+ */
+static void
+create_tblspc_symlink(char *filename)
+{
+	int			i;
+
+	for (i = 0; i < tablespacecount; i++)
+	{
+		char	   *tsoid = PQgetvalue(tablespacehdr, i, 0);
+
+		if (strstr(filename, tsoid) != NULL)
+		{
+			char	   *linkloc = psprintf("%s/%s", basedir, filename);
+			const char *mapped_tblspc_path = get_tablespace_mapping(PQgetvalue(tablespacehdr, i, 1));
+
+#ifdef HAVE_SYMLINK
+			if (symlink(mapped_tblspc_path, linkloc) != 0)
+			{
+				pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
+							 linkloc, mapped_tblspc_path);
+				exit(1);
+			}
+#else
+			pg_log_error("symlinks are not supported on this platform");
+			exit(1);
+#endif
+			free(linkloc);
+			break;
+		}
+	}
+}
+
+/*
+ * General function for writing to a file; creates one if it doesn't exist
+ */
+static void
+writefile(char *path, char *buf)
+{
+	FILE	   *f;
+	char		pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
-- 
2.21.0 (Apple Git-122.2)

0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v7.patchapplication/octet-stream; name=0002-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v7.patchDownload
From 3184318ba43a238d5ca67cb46b0d72e632cd8f96 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 16:45:28 +0500
Subject: [PATCH 2/7] Rename sizeonly to dryrun for few functions in
 basebackup.

---
 src/backend/replication/basebackup.c | 44 ++++++++++++++--------------
 src/include/replication/basebackup.h |  2 +-
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index ea87676405..5774117089 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -54,15 +54,15 @@ typedef struct
 } basebackup_options;
 
 
-static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
+static int64 sendDir(const char *path, int basepathlen, bool dryrun,
 					 List *tablespaces, bool sendtblspclinks);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
 static int64 _tarWriteHeader(const char *filename, const char *linktarget,
-							 struct stat *statbuf, bool sizeonly);
+							 struct stat *statbuf, bool dryrun);
 static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-						  bool sizeonly);
+						  bool dryrun);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void base_backup_cleanup(int code, Datum arg);
@@ -959,13 +959,13 @@ sendFileWithContent(const char *filename, const char *content)
 
 /*
  * Include the tablespace directory pointed to by 'path' in the output tar
- * stream.  If 'sizeonly' is true, we just calculate a total length and return
+ * stream.  If 'dryrun' is true, we just calculate a total length and return
  * it, without actually sending anything.
  *
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool dryrun)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -995,17 +995,17 @@ sendTablespace(char *path, bool sizeonly)
 	}
 
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
-						   sizeonly);
+						   dryrun);
 
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
 
 	return size;
 }
 
 /*
  * Include all files from the given directory in the output tar stream. If
- * 'sizeonly' is true, we just calculate a total length and return it, without
+ * 'dryrun' is true, we just calculate a total length and return it, without
  * actually sending anything.
  *
  * Omit any directory in the tablespaces list, to avoid backing up
@@ -1016,7 +1016,7 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		bool sendtblspclinks)
 {
 	DIR		   *dir;
@@ -1171,7 +1171,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
-				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
 			}
@@ -1187,7 +1187,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
 
@@ -1199,14 +1199,14 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (strcmp(pathbuf, "./pg_wal") == 0)
 		{
 			/* If pg_wal is a symlink, write it as a directory anyway */
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 
 			/*
 			 * Also send archive_status directory (by hackishly reusing
 			 * statbuf from above ...).
 			 */
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			continue;			/* don't recurse into pg_wal */
 		}
@@ -1238,7 +1238,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			linkpath[rllen] = '\0';
 
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
-									&statbuf, sizeonly);
+									&statbuf, dryrun);
 #else
 
 			/*
@@ -1262,7 +1262,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 * permissions right.
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1293,17 +1293,17 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			if (!dryrun)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? pg_atoi(lastDir + 1, sizeof(Oid), 0) : InvalidOid);
 
-			if (sent || sizeonly)
+			if (sent || dryrun)
 			{
 				/* Add size, rounded up to 512byte block */
 				size += ((statbuf.st_size + 511) & ~511);
@@ -1612,12 +1612,12 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
 
 static int64
 _tarWriteHeader(const char *filename, const char *linktarget,
-				struct stat *statbuf, bool sizeonly)
+				struct stat *statbuf, bool dryrun)
 {
 	char		h[512];
 	enum tarError rc;
 
-	if (!sizeonly)
+	if (!dryrun)
 	{
 		rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
 							 statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
@@ -1654,7 +1654,7 @@ _tarWriteHeader(const char *filename, const char *linktarget,
  */
 static int64
 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-			 bool sizeonly)
+			 bool dryrun)
 {
 	/* If symlink, write it as a directory anyway */
 #ifndef WIN32
@@ -1664,7 +1664,7 @@ _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
 #endif
 		statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
 
-	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
+	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, dryrun);
 }
 
 /*
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 503a5b9f0b..b55917b9b6 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool dryrun);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.0 (Apple Git-122.2)

0001-removed-PG_ENSURE_ERROR_CLEANUP-macro-from-basebacku_v7.patchapplication/octet-stream; name=0001-removed-PG_ENSURE_ERROR_CLEANUP-macro-from-basebacku_v7.patchDownload
From 3830d0e89293d6f8a87fe5facc9c2c64209a2e3e Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 10:21:38 +0500
Subject: [PATCH 1/7] removed PG_ENSURE_ERROR_CLEANUP macro from basebackup,
 instead registered base_backup_cleanup with before_shmem_exit handler. This
 will make sure that cleanup is always done when wal sender exits.

---
 src/backend/replication/basebackup.c | 182 +++++++++++++--------------
 1 file changed, 90 insertions(+), 92 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 1fa4551eff..ea87676405 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -243,6 +243,8 @@ perform_base_backup(basebackup_options *opt)
 	StringInfo	tblspc_map_file = NULL;
 	int			datadirpathlen;
 	List	   *tablespaces = NIL;
+	ListCell   *lc;
+	tablespaceinfo *ti;
 
 	datadirpathlen = strlen(DataDir);
 
@@ -261,121 +263,117 @@ perform_base_backup(basebackup_options *opt)
 	/*
 	 * Once do_pg_start_backup has been called, ensure that any failure causes
 	 * us to abort the backup so we don't "leak" a backup counter. For this
-	 * reason, *all* functionality between do_pg_start_backup() and the end of
-	 * do_pg_stop_backup() should be inside the error cleanup block!
+	 * reason, register base_backup_cleanup with before_shmem_exit handler.
+	 * This will make sure that call is always made when process exits. In
+	 * success, do_pg_stop_backup will have taken the system out of backup
+	 * mode and this callback will have no effect, Otherwise the required
+	 * cleanup will be done in any case.
 	 */
+	before_shmem_exit(base_backup_cleanup, (Datum) 0);
 
-	PG_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
-	{
-		ListCell   *lc;
-		tablespaceinfo *ti;
-
-		SendXlogRecPtrResult(startptr, starttli);
+	SendXlogRecPtrResult(startptr, starttli);
 
-		/*
-		 * Calculate the relative path of temporary statistics directory in
-		 * order to skip the files which are located in that directory later.
-		 */
-		if (is_absolute_path(pgstat_stat_directory) &&
-			strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
-		else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
-			statrelpath = psprintf("./%s", pgstat_stat_directory);
-		else
-			statrelpath = pgstat_stat_directory;
-
-		/* Add a node for the base directory at the end */
-		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
-		tablespaces = lappend(tablespaces, ti);
+	/*
+	 * Calculate the relative path of temporary statistics directory in order
+	 * to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
 
-		/* Send tablespace header */
-		SendBackupHeader(tablespaces);
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+	tablespaces = lappend(tablespaces, ti);
 
-		/* Setup and activate network throttling, if client requested it */
-		if (opt->maxrate > 0)
-		{
-			throttling_sample =
-				(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
+	/* Send tablespace header */
+	SendBackupHeader(tablespaces);
 
-			/*
-			 * The minimum amount of time for throttling_sample bytes to be
-			 * transferred.
-			 */
-			elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
-
-			/* Enable throttling. */
-			throttling_counter = 0;
+	/* Setup and activate network throttling, if client requested it */
+	if (opt->maxrate > 0)
+	{
+		throttling_sample =
+			(int64) opt->maxrate * (int64) 1024 / THROTTLING_FREQUENCY;
 
-			/* The 'real data' starts now (header was ignored). */
-			throttled_last = GetCurrentTimestamp();
-		}
-		else
-		{
-			/* Disable throttling. */
-			throttling_counter = -1;
-		}
+		/*
+		 * The minimum amount of time for throttling_sample bytes to be
+		 * transferred.
+		 */
+		elapsed_min_unit = USECS_PER_SEC / THROTTLING_FREQUENCY;
 
-		/* Send off our tablespaces one by one */
-		foreach(lc, tablespaces)
-		{
-			tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
-			StringInfoData buf;
+		/* Enable throttling. */
+		throttling_counter = 0;
 
-			/* Send CopyOutResponse message */
-			pq_beginmessage(&buf, 'H');
-			pq_sendbyte(&buf, 0);	/* overall format */
-			pq_sendint16(&buf, 0);	/* natts */
-			pq_endmessage(&buf);
+		/* The 'real data' starts now (header was ignored). */
+		throttled_last = GetCurrentTimestamp();
+	}
+	else
+	{
+		/* Disable throttling. */
+		throttling_counter = -1;
+	}
 
-			if (ti->path == NULL)
-			{
-				struct stat statbuf;
+	/* Send off our tablespaces one by one */
+	foreach(lc, tablespaces)
+	{
+		tablespaceinfo *ti = (tablespaceinfo *) lfirst(lc);
+		StringInfoData buf;
 
-				/* In the main tar, include the backup_label first... */
-				sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
+		/* Send CopyOutResponse message */
+		pq_beginmessage(&buf, 'H');
+		pq_sendbyte(&buf, 0);	/* overall format */
+		pq_sendint16(&buf, 0);	/* natts */
+		pq_endmessage(&buf);
 
-				/*
-				 * Send tablespace_map file if required and then the bulk of
-				 * the files.
-				 */
-				if (tblspc_map_file && opt->sendtblspcmapfile)
-				{
-					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-					sendDir(".", 1, false, tablespaces, false);
-				}
-				else
-					sendDir(".", 1, false, tablespaces, true);
+		if (ti->path == NULL)
+		{
+			struct stat statbuf;
 
-				/* ... and pg_control after everything else. */
-				if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
-					ereport(ERROR,
-							(errcode_for_file_access(),
-							 errmsg("could not stat file \"%s\": %m",
-									XLOG_CONTROL_FILE)));
-				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
-			}
-			else
-				sendTablespace(ti->path, false);
+			/* In the main tar, include the backup_label first... */
+			sendFileWithContent(BACKUP_LABEL_FILE, labelfile->data);
 
 			/*
-			 * If we're including WAL, and this is the main data directory we
-			 * don't terminate the tar stream here. Instead, we will append
-			 * the xlog files below and terminate it then. This is safe since
-			 * the main data directory is always sent *last*.
+			 * Send tablespace_map file if required and then the bulk of the
+			 * files.
 			 */
-			if (opt->includewal && ti->path == NULL)
+			if (tblspc_map_file && opt->sendtblspcmapfile)
 			{
-				Assert(lnext(tablespaces, lc) == NULL);
+				sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
+				sendDir(".", 1, false, tablespaces, false);
 			}
 			else
-				pq_putemptymessage('c');	/* CopyDone */
+				sendDir(".", 1, false, tablespaces, true);
+
+			/* ... and pg_control after everything else. */
+			if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file \"%s\": %m",
+								XLOG_CONTROL_FILE)));
+			sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 		}
+		else
+			sendTablespace(ti->path, false);
 
-		endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+		/*
+		 * If we're including WAL, and this is the main data directory we
+		 * don't terminate the tar stream here. Instead, we will append the
+		 * xlog files below and terminate it then. This is safe since the main
+		 * data directory is always sent *last*.
+		 */
+		if (opt->includewal && ti->path == NULL)
+		{
+			Assert(lnext(tablespaces, lc) == NULL);
+		}
+		else
+			pq_putemptymessage('c');	/* CopyDone */
 	}
-	PG_END_ENSURE_ERROR_CLEANUP(base_backup_cleanup, (Datum) 0);
 
+	endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
 
 	if (opt->includewal)
 	{
-- 
2.21.0 (Apple Git-122.2)

#40Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#39)
Re: WIP/PoC for parallel backup

On Thu, Dec 12, 2019 at 10:20 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

I have updated the patches (v7 attached) and have taken care of all issues pointed by Jeevan, additionally
ran the pgindent on each patch. Furthermore, Command names have been renamed as suggested and I
have simplified the SendFiles function. Client can only request the regular files, any other kind such as
directories or symlinks will be skipped, the client will be responsible for taking care of such.

Hi,

Patch 0001 of this series conflicts with my recent commit
303640199d0436c5e7acdf50b837a027b5726594; that commit was actually
inspired by some previous study of 0001. That being said, I think 0001
has the wrong idea. There's no reason that I can see why it should be
correct to remove the PG_ENSURE_ERROR_CLEANUP calls from
perform_base_backup(). It's true that if we register a long-lived
before_shmem_exit hook, then the backup will get cleaned up even
without the PG_ENSURE_ERROR_CLEANUP block, but there's also the
question of the warning message. I think that our goal should be to
emit the warning message about a backup being stopped too early if the
user uses either pg_start_backup() or the new START_BACKUP command and
does not end the backup with either pg_stop_backup() or the new
STOP_BACKUP command -- but not if a single command that both starts
and ends a backup, like BASE_BACKUP, is interrupted. To accomplish
that goal in the wake of 303640199d0436c5e7acdf50b837a027b5726594, we
need to temporarily register do_pg_abort_backup() as a
before_shmem_exit() handler using PG_ENSURE_ERROR_CLEANUP() during
commands like BASE_BACKUP() -- and for things like pg_start_backup()
or the new START_BACKUP command, we just need to add a single call to
register_persistent_abort_backup_handler().

So I think you can drop 0001, and then in the patch that actually
introduces START_BACKUP, add the call to
register_persistent_abort_backup_handler() before calling
do_pg_start_backup(). Also in that patch, also adjust the warning text
that do_pg_abort_backup() emits to be more generic e.g. "aborting
backup due to backend exiting while a non-exclusive backup is in
progress".

0003 creates three new functions, moving code from
do_pg_start_backup() to a new function collectTablespaces() and from
perform_base_backup() to new functions setup_throttle() and
include_wal_files(). I'm skeptical about all of these changes. One
general nitpick is that the way these function names are capitalized
and punctuated does not seem to have been chosen very consistently;
how about name_like_this() throughout? A bit more substantively:

- collectTablespaces() is factored out of do_pg_start_backup() so that
it can also be used by SendFileList(), but that means that a client is
going to invoke START_BACKUP, indirectly calling collectTablespaces(),
and then immediately afterward the client is probably going to call
SEND_FILE_LIST, which will again call collectTablespaces(). That does
not appear to be super-great. For one thing, it's duplicate work,
although because SendFileList() is going to pass infotbssize as false,
it's not a lot of duplicated work. Also, what happens if the two calls
to collectTablespaces() return different answers due to concurrent
CREATE/DROP TABLESPACE commands? Maybe it would all work out fine, but
it seems like there is at least the possibility of bugs if different
parts of the backup have different notions of what tablespaces exist.

- setup_throttle() is factored out of perform_base_backup() so that it
can be called in StartBackup() and StopBackup() and SendFiles(). This
seems extremely odd. Why does it make any sense to give the user an
option to activate throttling when *ending* a backup? Why does it make
sense to give the user a chance to enable throttling *both* at the
startup of a backup *and also* for each individual file. If we're
going to support throttling here, it seems like it should be either a
backup-level property or a file-level property, not both.

- include_wal_files() is factored out of perform_base_backup() so that
it can be called by StopBackup(). This seems like a poor design
decision. The idea behind the BASE_BACKUP command is that you run that
one command, and the server sends you everything. The idea in this new
way of doing business is that the client requests the individual files
it wants -- except for the WAL files, which are for some reason not
requested individually but sent all together as part of the
STOP_BACKUP response. It seems like it would be more consistent if the
client were to decide which WAL files it needs and request them one by
one, just as we do with other files.

I think there's a common theme to all of these complaints, which is
that you haven't done enough to move things that are the
responsibility of the backend in the BASE_BACKUP model to the frontend
in this model. I started wondering, for example, whether it might not
be better to have the client rather than the server construct the
tablespace_map file. After all, the client needs to get the list of
files anyway (hence SEND_FILE_LIST) and if it's got that then it knows
almost enough to construct the tablespace map. The only additional
thing it needs is the full pathname to which the link points. But, it
seems that we could fairly easily extend SEND_FILE_LIST to send, for
files that are symbolic links, the target of the link, using a new
column. Or alternatively, using a separate command, so that instead of
just sending a single SEND_FILE_LIST command, the client might first
ask for a tablespace list and then might ask for a list of files
within each tablespace (e.g. LIST_TABLESPACES, then LIST_FILES <oid>
for each tablespace, with 0 for the main tablespace, perhaps). I'm not
sure which way is better.

Similarly, for throttling, I have a hard time understanding how what
you've got here is going to work reasonably. It looks like each client
is just going to request whatever MAX_RATE the user specifies, but the
result of that will be that the actual transfer rate is probably a
multiple of the specified rate, approximately equal to the specified
rate times the number of clients. That's probably not what the user
wants. You could take the specified rate and divide it by the number
of workers, but limiting each of 4 workers to a quarter of the rate
will probably lead to a combined rate of less than than the specified
rate, because if one worker doesn't use all of the bandwidth to which
it's entitled, or even exits earlier than the others, the other
workers don't get to go any faster as a result. Another problem is
that, in the current approach, throttling applies overall to the
entire backup, but in this approach, it is applied separately to each
SEND_FILE command. In the current approach, if one file finishes a
little faster or slower than anticipated, the next file in the tarball
will be sent a little slower or faster to compensate. But in this
approach, each SEND_FILES command is throttled separately, so this
property is lost. Furthermore, while BASEBACKUP sends data
continuously, this approach naturally involves pauses between
commands. If files are large, that won't matter much, but if they're
small and numerous, it will tend to cause the actual transfer rate to
be less than the throttling rate.

One potential way to solve this problem is... move it to the client
side. Instead of making it the server's job not to send data too fast,
make it the client's job not to receive data too fast. Let the server
backends write as fast as they want, and on the pg_basebackup side,
have the threads coordinate with each other so that they don't read
data faster than the configured rate. That's not quite the same thing,
though, because the server can get ahead by the size of the client's
receive buffers plus whatever data is on the wire. I don't know
whether that's a big enough problem to be worth caring about. If it
is, then I think we need some server infrastructure to "group
throttle" a group of cooperating backends.

A general comment about 0004 is that it seems like you've proceeded by
taking the code from perform_base_backup() and spreading it across
several different functions without, necessarily, as much thought as
is needed there. For instance, StartBackup() looks like just the
beginning of perform_base_backup(). But, why shouldn't it instead look
like pg_start_backup() -- in fact, a simplified version that only
handles the non-exclusive backup case? Is the extra stuff it's doing
really appropriate? I've already complained about the
tablespace-related stuff here and the throttling, but there's more.
Setting statrelpath here will probably break if somebody tries to use
SEND_FILES without first calling START_BACKUP. Sending the
backup_label file here is oddly asymmetric, because that's done by
pg_stop_backup(), not pg_start_backup(). And similarly, StopBackup()
looks like it's just the end of perform_base_backup(), but that's not
pretty strange-looking too. Again, I've already complained about
include_wal_files() being part of this, but there's also:

+ /* ... and pg_control after everything else. */

...which (1) is an odd thing to say when this is the first thing this
particular function is to send and (2) is another example of a sloppy
division of labor between client and server; apparently, the client is
supposed to know not to request pg_control, because the server is
going to send it unsolicited. There's no particular reason to have
this a special case. The client could just request it last. And then
the server code wouldn't need a special case, and you wouldn't have
this odd logic split between the client and the server.

Overall, I think this needs a lot more work. The overall idea's not
wrong, but there seem to be a very large number of details which, at
least to me, do not seem to be correct.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#41Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#40)
Re: WIP/PoC for parallel backup

On Thu, Dec 19, 2019 at 10:47 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Dec 12, 2019 at 10:20 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I have updated the patches (v7 attached) and have taken care of all

issues pointed by Jeevan, additionally

ran the pgindent on each patch. Furthermore, Command names have been

renamed as suggested and I

have simplified the SendFiles function. Client can only request the

regular files, any other kind such as

directories or symlinks will be skipped, the client will be responsible

for taking care of such.

Hi,

Patch 0001 of this series conflicts with my recent commit
303640199d0436c5e7acdf50b837a027b5726594; that commit was actually
inspired by some previous study of 0001. That being said, I think 0001
has the wrong idea. There's no reason that I can see why it should be
correct to remove the PG_ENSURE_ERROR_CLEANUP calls from
perform_base_backup(). It's true that if we register a long-lived
before_shmem_exit hook, then the backup will get cleaned up even
without the PG_ENSURE_ERROR_CLEANUP block, but there's also the
question of the warning message. I think that our goal should be to
emit the warning message about a backup being stopped too early if the
user uses either pg_start_backup() or the new START_BACKUP command and
does not end the backup with either pg_stop_backup() or the new
STOP_BACKUP command -- but not if a single command that both starts
and ends a backup, like BASE_BACKUP, is interrupted. To accomplish
that goal in the wake of 303640199d0436c5e7acdf50b837a027b5726594, we
need to temporarily register do_pg_abort_backup() as a
before_shmem_exit() handler using PG_ENSURE_ERROR_CLEANUP() during
commands like BASE_BACKUP() -- and for things like pg_start_backup()
or the new START_BACKUP command, we just need to add a single call to
register_persistent_abort_backup_handler().

So I think you can drop 0001, and then in the patch that actually
introduces START_BACKUP, add the call to
register_persistent_abort_backup_handler() before calling
do_pg_start_backup(). Also in that patch, also adjust the warning text
that do_pg_abort_backup() emits to be more generic e.g. "aborting
backup due to backend exiting while a non-exclusive backup is in
progress".

Sure. will do.

0003 creates three new functions, moving code from
do_pg_start_backup() to a new function collectTablespaces() and from
perform_base_backup() to new functions setup_throttle() and
include_wal_files(). I'm skeptical about all of these changes. One
general nitpick is that the way these function names are capitalized
and punctuated does not seem to have been chosen very consistently;
how about name_like_this() throughout? A bit more substantively:

- collectTablespaces() is factored out of do_pg_start_backup() so that
it can also be used by SendFileList(), but that means that a client is
going to invoke START_BACKUP, indirectly calling collectTablespaces(),
and then immediately afterward the client is probably going to call
SEND_FILE_LIST, which will again call collectTablespaces(). That does
not appear to be super-great. For one thing, it's duplicate work,
although because SendFileList() is going to pass infotbssize as false,
it's not a lot of duplicated work.

I'll remove this duplication by eliminating this call from START_BACKUP and
SEND_FILE_LIST functions. More about this is explained later in this email.

Also, what happens if the two calls
to collectTablespaces() return different answers due to concurrent
CREATE/DROP TABLESPACE commands? Maybe it would all work out fine, but
it seems like there is at least the possibility of bugs if different
parts of the backup have different notions of what tablespaces exist.

The concurrent CREATE/DROP TABLESPACE commands, it can happen and will
be resolved by the WAL files collected for the backup. I don't think we
can do anything when objects are created or dropped in-between start and
stop backup. BASE_BACKUPalso relies on the WAL files to handle such a
scenario and does not error out when some relation files go away.

- setup_throttle() is factored out of perform_base_backup() so that it
can be called in StartBackup() and StopBackup() and SendFiles(). This
seems extremely odd. Why does it make any sense to give the user an
option to activate throttling when *ending* a backup? Why does it make
sense to give the user a chance to enable throttling *both* at the
startup of a backup *and also* for each individual file. If we're
going to support throttling here, it seems like it should be either a
backup-level property or a file-level property, not both.

It's a file-level property only. Throttle functionality relies on global
variables. StartBackup() and StopBackup() are calling setup_throttle
function to disable the throttling.

I should have been more explicit here by using -1 to setup_throttle,
Illustrating that throttling is disabled, instead of using 'opt->maxrate'.
(Although it defaults to -1 for these functions).

I'll remove the setup_throttle() call for both functions.

- include_wal_files() is factored out of perform_base_backup() so that
it can be called by StopBackup(). This seems like a poor design
decision. The idea behind the BASE_BACKUP command is that you run that
one command, and the server sends you everything. The idea in this new
way of doing business is that the client requests the individual files
it wants -- except for the WAL files, which are for some reason not
requested individually but sent all together as part of the
STOP_BACKUP response. It seems like it would be more consistent if the
client were to decide which WAL files it needs and request them one by
one, just as we do with other files.

As I understand you are suggesting to add another command to fetch the
list of WAL files which would be called by the client after executing stop
backup. Once the client gets that list, it starts requesting the WAL files
one
by one.

So I will add LIST_WAL_FILES command that will take start_lsn and end_lsn
as arguments and return the list of WAL files between these LSNs.

Something like this :
LIST_WAL_FILES 'start_lsn' 'end_lsn';

I think there's a common theme to all of these complaints, which is
that you haven't done enough to move things that are the
responsibility of the backend in the BASE_BACKUP model to the frontend
in this model. I started wondering, for example, whether it might not
be better to have the client rather than the server construct the
tablespace_map file. After all, the client needs to get the list of
files anyway (hence SEND_FILE_LIST) and if it's got that then it knows
almost enough to construct the tablespace map. The only additional
thing it needs is the full pathname to which the link points. But, it
seems that we could fairly easily extend SEND_FILE_LIST to send, for
files that are symbolic links, the target of the link, using a new
column. Or alternatively, using a separate command, so that instead of
just sending a single SEND_FILE_LIST command, the client might first
ask for a tablespace list and then might ask for a list of files
within each tablespace (e.g. LIST_TABLESPACES, then LIST_FILES <oid>
for each tablespace, with 0 for the main tablespace, perhaps). I'm not
sure which way is better.

do_pg_start_backup is collecting the tablespace information anyway to
build the tablespace_map for BASE_BACKUP. So returning the same seemed
better than adding a new command for the same information. hence multiple
calls to the collectTablespaces() [to be renamed to collect_tablespaces].

tablespace_map can be constructed by the client, but then BASE_BACKUP
is returning it as part of the full backup. If clients in parallel mode
are to construct this themselves, these will seem like two different
approaches. Perhaps this should be done for BASE_BACKUP as
well?

I'll refactor the do_pg_start_backup function to remove the code related
to tablespace information collection (to collect_tablespaces) and
tablespace_map file creation, so that this function does not collect this
information unnecessarily. perform_base_backup function can collect and
send the tablespace information to the client and then the client can
construct the tablespace_map file.

I'll add a new command to fetch the list of tablespaces i.e.
LIST_TABLESPACES
which will return the tablespace information to the client for parallel
mode. And will refactor START_BACKUP and STOP_BACKUP commands,
so that they only do the specific job of putting the system in backup mode
or
out of it, nothing else.These commands should only return the start and end
LSN to the client.

Similarly, for throttling, I have a hard time understanding how what
you've got here is going to work reasonably. It looks like each client
is just going to request whatever MAX_RATE the user specifies, but the
result of that will be that the actual transfer rate is probably a
multiple of the specified rate, approximately equal to the specified
rate times the number of clients. That's probably not what the user
wants. You could take the specified rate and divide it by the number
of workers, but limiting each of 4 workers to a quarter of the rate
will probably lead to a combined rate of less than than the specified
rate, because if one worker doesn't use all of the bandwidth to which
it's entitled, or even exits earlier than the others, the other
workers don't get to go any faster as a result. Another problem is
that, in the current approach, throttling applies overall to the
entire backup, but in this approach, it is applied separately to each
SEND_FILE command. In the current approach, if one file finishes a
little faster or slower than anticipated, the next file in the tarball
will be sent a little slower or faster to compensate. But in this
approach, each SEND_FILES command is throttled separately, so this
property is lost. Furthermore, while BASEBACKUP sends data
continuously, this approach naturally involves pauses between
commands. If files are large, that won't matter much, but if they're
small and numerous, it will tend to cause the actual transfer rate to
be less than the throttling rate.

One potential way to solve this problem is... move it to the client
side. Instead of making it the server's job not to send data too fast,
make it the client's job not to receive data too fast. Let the server
backends write as fast as they want, and on the pg_basebackup side,
have the threads coordinate with each other so that they don't read
data faster than the configured rate. That's not quite the same thing,
though, because the server can get ahead by the size of the client's
receive buffers plus whatever data is on the wire. I don't know
whether that's a big enough problem to be worth caring about. If it
is, then I think we need some server infrastructure to "group
throttle" a group of cooperating backends.

That was a mistake in my code. maxrate should've been equally divided
amongst all threads. I agree that we should move this to the client-side.
When a thread exits, its share should also be equally divided amongst
the remaining threads (i.e. recalculate maxrate for each remaining thread).

Say we have 4 running threads with each allocation 25% of the bandwidth.
Thread 1 exits. We recalculate bandwidth and assign the remaining 3 threads
33.33% each. This solves one problem that you had identified. However,
it doesn't solve where one (or more) thread is not fully consuming their
allocated share. I'm not really sure how we can solve it properly.
Suggestions
are welcome.

A general comment about 0004 is that it seems like you've proceeded by
taking the code from perform_base_backup() and spreading it across
several different functions without, necessarily, as much thought as
is needed there. For instance, StartBackup() looks like just the
beginning of perform_base_backup(). But, why shouldn't it instead look
like pg_start_backup() -- in fact, a simplified version that only
handles the non-exclusive backup case? Is the extra stuff it's doing
really appropriate? I've already complained about the
tablespace-related stuff here and the throttling, but there's more.
Setting statrelpath here will probably break if somebody tries to use
SEND_FILES without first calling START_BACKUP. Sending the
backup_label file here is oddly asymmetric, because that's done by
pg_stop_backup(), not pg_start_backup(). And similarly, StopBackup()
looks like it's just the end of perform_base_backup(), but that's not
pretty strange-looking too. Again, I've already complained about
include_wal_files() being part of this, but there's also:

+ /* ... and pg_control after everything else. */

...which (1) is an odd thing to say when this is the first thing this
particular function is to send and (2) is another example of a sloppy
division of labor between client and server; apparently, the client is
supposed to know not to request pg_control, because the server is
going to send it unsolicited. There's no particular reason to have
this a special case. The client could just request it last. And then
the server code wouldn't need a special case, and you wouldn't have
this odd logic split between the client and the server.

Overall, I think this needs a lot more work. The overall idea's not
wrong, but there seem to be a very large number of details which, at
least to me, do not seem to be correct.

Thank you Robert for the detailed review. I really appreciate your insights
and very precise feedback.

After the changes suggested above, the design on a high level will look
something
like this:

=== SEQUENTIAL EXECUTION ===
START_BACKUP [LABEL | FAST]
- Starts backup on the server
- Returns the start LSN to client

LIST_TABLESPACES
- Sends a list of all tables spaces to client

Loops over LIST_TABLESPACES
- LIST_FILES [tablespace]
- Sends file list for the given tablespace
- Create a list of all files

=== PARALLEL EXECUTION ===
Thread loop until the list of files is exhausted
SEND_FILE <file(s)> [CHECKSUM | WAL_START_LOCATION]
- If the checksum is enabled then WAL_START_LOCATION is required.
- Can request server to send one or more files but we are requesting one at
a time
- Pick next file from list of files

- Threads sleep after the list is exhausted
- All threads are sleeping

=== SEQUENTIAL EXECUTION ===
STOP_BACKUP [NOWAIT]
- Stops backup mode
- Return end LSN

If --wal-method=fetch then
LIST_WAL_FILES 'start_lsn' 'end_lsn'
- Sends a list of WAL files between start LSN and end LSN

=== PARALLEL EXECUTION ===
Thread loop until the list of WAL files is exhausted
SEND_FILE <WAL file>
- Can request server to send one or more files but we are requesting one
WAL file at a time
- Pick next file from list of WAL files

- Threads terminate and set their status as completed/terminated

=== SEQUENTIAL EXECUTION ===
Cleanup

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#42Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#41)
5 attachment(s)
Re: WIP/PoC for parallel backup

On Sat, Jan 4, 2020 at 11:53 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Thu, Dec 19, 2019 at 10:47 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Dec 12, 2019 at 10:20 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I have updated the patches (v7 attached) and have taken care of all

issues pointed by Jeevan, additionally

ran the pgindent on each patch. Furthermore, Command names have been

renamed as suggested and I

have simplified the SendFiles function. Client can only request the

regular files, any other kind such as

directories or symlinks will be skipped, the client will be responsible

for taking care of such.

Hi,

Patch 0001 of this series conflicts with my recent commit
303640199d0436c5e7acdf50b837a027b5726594; that commit was actually
inspired by some previous study of 0001. That being said, I think 0001
has the wrong idea. There's no reason that I can see why it should be
correct to remove the PG_ENSURE_ERROR_CLEANUP calls from
perform_base_backup(). It's true that if we register a long-lived
before_shmem_exit hook, then the backup will get cleaned up even
without the PG_ENSURE_ERROR_CLEANUP block, but there's also the
question of the warning message. I think that our goal should be to
emit the warning message about a backup being stopped too early if the
user uses either pg_start_backup() or the new START_BACKUP command and
does not end the backup with either pg_stop_backup() or the new
STOP_BACKUP command -- but not if a single command that both starts
and ends a backup, like BASE_BACKUP, is interrupted. To accomplish
that goal in the wake of 303640199d0436c5e7acdf50b837a027b5726594, we
need to temporarily register do_pg_abort_backup() as a
before_shmem_exit() handler using PG_ENSURE_ERROR_CLEANUP() during
commands like BASE_BACKUP() -- and for things like pg_start_backup()
or the new START_BACKUP command, we just need to add a single call to
register_persistent_abort_backup_handler().

So I think you can drop 0001, and then in the patch that actually
introduces START_BACKUP, add the call to
register_persistent_abort_backup_handler() before calling
do_pg_start_backup(). Also in that patch, also adjust the warning text
that do_pg_abort_backup() emits to be more generic e.g. "aborting
backup due to backend exiting while a non-exclusive backup is in
progress".

Sure. will do.

0003 creates three new functions, moving code from
do_pg_start_backup() to a new function collectTablespaces() and from
perform_base_backup() to new functions setup_throttle() and
include_wal_files(). I'm skeptical about all of these changes. One
general nitpick is that the way these function names are capitalized
and punctuated does not seem to have been chosen very consistently;
how about name_like_this() throughout? A bit more substantively:

- collectTablespaces() is factored out of do_pg_start_backup() so that
it can also be used by SendFileList(), but that means that a client is
going to invoke START_BACKUP, indirectly calling collectTablespaces(),
and then immediately afterward the client is probably going to call
SEND_FILE_LIST, which will again call collectTablespaces(). That does
not appear to be super-great. For one thing, it's duplicate work,
although because SendFileList() is going to pass infotbssize as false,
it's not a lot of duplicated work.

I'll remove this duplication by eliminating this call from START_BACKUP and
SEND_FILE_LIST functions. More about this is explained later in this email.

Also, what happens if the two calls
to collectTablespaces() return different answers due to concurrent
CREATE/DROP TABLESPACE commands? Maybe it would all work out fine, but
it seems like there is at least the possibility of bugs if different
parts of the backup have different notions of what tablespaces exist.

The concurrent CREATE/DROP TABLESPACE commands, it can happen and will
be resolved by the WAL files collected for the backup. I don't think we
can do anything when objects are created or dropped in-between start and
stop backup. BASE_BACKUPalso relies on the WAL files to handle such a
scenario and does not error out when some relation files go away.

- setup_throttle() is factored out of perform_base_backup() so that it
can be called in StartBackup() and StopBackup() and SendFiles(). This
seems extremely odd. Why does it make any sense to give the user an
option to activate throttling when *ending* a backup? Why does it make
sense to give the user a chance to enable throttling *both* at the
startup of a backup *and also* for each individual file. If we're
going to support throttling here, it seems like it should be either a
backup-level property or a file-level property, not both.

It's a file-level property only. Throttle functionality relies on global
variables. StartBackup() and StopBackup() are calling setup_throttle
function to disable the throttling.

I should have been more explicit here by using -1 to setup_throttle,
Illustrating that throttling is disabled, instead of using 'opt->maxrate'.
(Although it defaults to -1 for these functions).

I'll remove the setup_throttle() call for both functions.

- include_wal_files() is factored out of perform_base_backup() so that
it can be called by StopBackup(). This seems like a poor design
decision. The idea behind the BASE_BACKUP command is that you run that
one command, and the server sends you everything. The idea in this new
way of doing business is that the client requests the individual files
it wants -- except for the WAL files, which are for some reason not
requested individually but sent all together as part of the
STOP_BACKUP response. It seems like it would be more consistent if the
client were to decide which WAL files it needs and request them one by
one, just as we do with other files.

As I understand you are suggesting to add another command to fetch the
list of WAL files which would be called by the client after executing stop
backup. Once the client gets that list, it starts requesting the WAL files
one
by one.

So I will add LIST_WAL_FILES command that will take start_lsn and end_lsn
as arguments and return the list of WAL files between these LSNs.

Something like this :
LIST_WAL_FILES 'start_lsn' 'end_lsn';

I think there's a common theme to all of these complaints, which is
that you haven't done enough to move things that are the
responsibility of the backend in the BASE_BACKUP model to the frontend
in this model. I started wondering, for example, whether it might not
be better to have the client rather than the server construct the
tablespace_map file. After all, the client needs to get the list of
files anyway (hence SEND_FILE_LIST) and if it's got that then it knows
almost enough to construct the tablespace map. The only additional
thing it needs is the full pathname to which the link points. But, it
seems that we could fairly easily extend SEND_FILE_LIST to send, for
files that are symbolic links, the target of the link, using a new
column. Or alternatively, using a separate command, so that instead of
just sending a single SEND_FILE_LIST command, the client might first
ask for a tablespace list and then might ask for a list of files
within each tablespace (e.g. LIST_TABLESPACES, then LIST_FILES <oid>
for each tablespace, with 0 for the main tablespace, perhaps). I'm not
sure which way is better.

do_pg_start_backup is collecting the tablespace information anyway to
build the tablespace_map for BASE_BACKUP. So returning the same seemed
better than adding a new command for the same information. hence multiple
calls to the collectTablespaces() [to be renamed to collect_tablespaces].

tablespace_map can be constructed by the client, but then BASE_BACKUP
is returning it as part of the full backup. If clients in parallel mode
are to construct this themselves, these will seem like two different
approaches. Perhaps this should be done for BASE_BACKUP as
well?

I'll refactor the do_pg_start_backup function to remove the code related
to tablespace information collection (to collect_tablespaces) and
tablespace_map file creation, so that this function does not collect this
information unnecessarily. perform_base_backup function can collect and
send the tablespace information to the client and then the client can
construct the tablespace_map file.

I'll add a new command to fetch the list of tablespaces i.e.
LIST_TABLESPACES
which will return the tablespace information to the client for parallel
mode. And will refactor START_BACKUP and STOP_BACKUP commands,
so that they only do the specific job of putting the system in backup mode
or
out of it, nothing else.These commands should only return the start and end
LSN to the client.

Similarly, for throttling, I have a hard time understanding how what
you've got here is going to work reasonably. It looks like each client
is just going to request whatever MAX_RATE the user specifies, but the
result of that will be that the actual transfer rate is probably a
multiple of the specified rate, approximately equal to the specified
rate times the number of clients. That's probably not what the user
wants. You could take the specified rate and divide it by the number
of workers, but limiting each of 4 workers to a quarter of the rate
will probably lead to a combined rate of less than than the specified
rate, because if one worker doesn't use all of the bandwidth to which
it's entitled, or even exits earlier than the others, the other
workers don't get to go any faster as a result. Another problem is
that, in the current approach, throttling applies overall to the
entire backup, but in this approach, it is applied separately to each
SEND_FILE command. In the current approach, if one file finishes a
little faster or slower than anticipated, the next file in the tarball
will be sent a little slower or faster to compensate. But in this
approach, each SEND_FILES command is throttled separately, so this
property is lost. Furthermore, while BASEBACKUP sends data
continuously, this approach naturally involves pauses between
commands. If files are large, that won't matter much, but if they're
small and numerous, it will tend to cause the actual transfer rate to
be less than the throttling rate.

One potential way to solve this problem is... move it to the client
side. Instead of making it the server's job not to send data too fast,
make it the client's job not to receive data too fast. Let the server
backends write as fast as they want, and on the pg_basebackup side,
have the threads coordinate with each other so that they don't read
data faster than the configured rate. That's not quite the same thing,
though, because the server can get ahead by the size of the client's
receive buffers plus whatever data is on the wire. I don't know
whether that's a big enough problem to be worth caring about. If it
is, then I think we need some server infrastructure to "group
throttle" a group of cooperating backends.

That was a mistake in my code. maxrate should've been equally divided
amongst all threads. I agree that we should move this to the client-side.
When a thread exits, its share should also be equally divided amongst
the remaining threads (i.e. recalculate maxrate for each remaining
thread).

Say we have 4 running threads with each allocation 25% of the bandwidth.
Thread 1 exits. We recalculate bandwidth and assign the remaining 3 threads
33.33% each. This solves one problem that you had identified. However,
it doesn't solve where one (or more) thread is not fully consuming their
allocated share. I'm not really sure how we can solve it properly.
Suggestions
are welcome.

A general comment about 0004 is that it seems like you've proceeded by
taking the code from perform_base_backup() and spreading it across
several different functions without, necessarily, as much thought as
is needed there. For instance, StartBackup() looks like just the
beginning of perform_base_backup(). But, why shouldn't it instead look
like pg_start_backup() -- in fact, a simplified version that only
handles the non-exclusive backup case? Is the extra stuff it's doing
really appropriate? I've already complained about the
tablespace-related stuff here and the throttling, but there's more.
Setting statrelpath here will probably break if somebody tries to use
SEND_FILES without first calling START_BACKUP. Sending the
backup_label file here is oddly asymmetric, because that's done by
pg_stop_backup(), not pg_start_backup(). And similarly, StopBackup()
looks like it's just the end of perform_base_backup(), but that's not
pretty strange-looking too. Again, I've already complained about
include_wal_files() being part of this, but there's also:

+ /* ... and pg_control after everything else. */

...which (1) is an odd thing to say when this is the first thing this
particular function is to send and (2) is another example of a sloppy
division of labor between client and server; apparently, the client is
supposed to know not to request pg_control, because the server is
going to send it unsolicited. There's no particular reason to have
this a special case. The client could just request it last. And then
the server code wouldn't need a special case, and you wouldn't have
this odd logic split between the client and the server.

Overall, I think this needs a lot more work. The overall idea's not
wrong, but there seem to be a very large number of details which, at
least to me, do not seem to be correct.

Thank you Robert for the detailed review. I really appreciate your insights
and very precise feedback.

After the changes suggested above, the design on a high level will look
something
like this:

=== SEQUENTIAL EXECUTION ===
START_BACKUP [LABEL | FAST]
- Starts backup on the server
- Returns the start LSN to client

LIST_TABLESPACES
- Sends a list of all tables spaces to client

Loops over LIST_TABLESPACES
- LIST_FILES [tablespace]
- Sends file list for the given tablespace
- Create a list of all files

=== PARALLEL EXECUTION ===
Thread loop until the list of files is exhausted
SEND_FILE <file(s)> [CHECKSUM | WAL_START_LOCATION]
- If the checksum is enabled then WAL_START_LOCATION is required.
- Can request server to send one or more files but we are requesting one
at a time
- Pick next file from list of files

- Threads sleep after the list is exhausted
- All threads are sleeping

=== SEQUENTIAL EXECUTION ===
STOP_BACKUP [NOWAIT]
- Stops backup mode
- Return end LSN

If --wal-method=fetch then
LIST_WAL_FILES 'start_lsn' 'end_lsn'
- Sends a list of WAL files between start LSN and end LSN

=== PARALLEL EXECUTION ===
Thread loop until the list of WAL files is exhausted
SEND_FILE <WAL file>
- Can request server to send one or more files but we are requesting one
WAL file at a time
- Pick next file from list of WAL files

- Threads terminate and set their status as completed/terminated

=== SEQUENTIAL EXECUTION ===
Cleanup

Here are the the updated patches, taking care of the issues pointed
earlier. This patch adds the following commands (with specified option):

START_BACKUP [LABEL '<label>'] [FAST]
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILES '(' FILE, FILE... ')' [START_WAL_LOCATION 'X/X']
[NOVERIFY_CHECKSUMS]

Parallel backup is not making any use of tablespace map, so I have
removed that option from the above commands. There is a patch pending
to remove the exclusive backup; we can further refactor the
do_pg_start_backup
function at that time, to remove the tablespace information and move the
creation of tablespace_map file to the client.

I have disabled the maxrate option for parallel backup. I intend to send
out a separate patch for it. Robert previously suggested to implement
throttling on the client-side. I found the original email thread [1]/messages/by-id/521B4B29.20009@2ndquadrant.com
where throttling was proposed and added to the server. In that thread,
it was originally implemented on the client-side, but per many suggestions,
it was moved to server-side.

So, I have a few suggestions on how we can implement this:

1- have another option for pg_basebackup (i.e. per-worker-maxrate) where
the user could choose the bandwidth allocation for each worker. This
approach
can be implemented on the client-side as well as on the server-side.

2- have the maxrate, be divided among workers equally at first. and the
let the main thread keep adjusting it whenever one of the workers finishes.
I believe this would only be possible if we handle throttling on the client.
Also, as I understand it, implementing this will introduce additional mutex
for handling of bandwidth consumption data so that rate may be adjusted
according to data received by threads.

[1]: /messages/by-id/521B4B29.20009@2ndquadrant.com
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchapplication/octet-stream; name=0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchDownload
From 4e6639ee5a2d0d519ef3755ba5efb1afbe7e6626 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 16:45:28 +0500
Subject: [PATCH 1/5] Rename sizeonly to dryrun for few functions in
 basebackup.

---
 src/backend/replication/basebackup.c | 44 ++++++++++++++--------------
 src/include/replication/basebackup.h |  2 +-
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index dea8aab45e..e90ca6184b 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -54,15 +54,15 @@ typedef struct
 } basebackup_options;
 
 
-static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
+static int64 sendDir(const char *path, int basepathlen, bool dryrun,
 					 List *tablespaces, bool sendtblspclinks);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
 static int64 _tarWriteHeader(const char *filename, const char *linktarget,
-							 struct stat *statbuf, bool sizeonly);
+							 struct stat *statbuf, bool dryrun);
 static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-						  bool sizeonly);
+						  bool dryrun);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void perform_base_backup(basebackup_options *opt);
@@ -949,13 +949,13 @@ sendFileWithContent(const char *filename, const char *content)
 
 /*
  * Include the tablespace directory pointed to by 'path' in the output tar
- * stream.  If 'sizeonly' is true, we just calculate a total length and return
+ * stream.  If 'dryrun' is true, we just calculate a total length and return
  * it, without actually sending anything.
  *
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool dryrun)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -985,17 +985,17 @@ sendTablespace(char *path, bool sizeonly)
 	}
 
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
-						   sizeonly);
+						   dryrun);
 
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
 
 	return size;
 }
 
 /*
  * Include all files from the given directory in the output tar stream. If
- * 'sizeonly' is true, we just calculate a total length and return it, without
+ * 'dryrun' is true, we just calculate a total length and return it, without
  * actually sending anything.
  *
  * Omit any directory in the tablespaces list, to avoid backing up
@@ -1006,7 +1006,7 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		bool sendtblspclinks)
 {
 	DIR		   *dir;
@@ -1161,7 +1161,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
-				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
 			}
@@ -1177,7 +1177,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
 
@@ -1189,14 +1189,14 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (strcmp(pathbuf, "./pg_wal") == 0)
 		{
 			/* If pg_wal is a symlink, write it as a directory anyway */
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 
 			/*
 			 * Also send archive_status directory (by hackishly reusing
 			 * statbuf from above ...).
 			 */
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			continue;			/* don't recurse into pg_wal */
 		}
@@ -1228,7 +1228,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			linkpath[rllen] = '\0';
 
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
-									&statbuf, sizeonly);
+									&statbuf, dryrun);
 #else
 
 			/*
@@ -1252,7 +1252,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 * permissions right.
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1283,17 +1283,17 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			if (!dryrun)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? atooid(lastDir + 1) : InvalidOid);
 
-			if (sent || sizeonly)
+			if (sent || dryrun)
 			{
 				/* Add size, rounded up to 512byte block */
 				size += ((statbuf.st_size + 511) & ~511);
@@ -1602,12 +1602,12 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
 
 static int64
 _tarWriteHeader(const char *filename, const char *linktarget,
-				struct stat *statbuf, bool sizeonly)
+				struct stat *statbuf, bool dryrun)
 {
 	char		h[512];
 	enum tarError rc;
 
-	if (!sizeonly)
+	if (!dryrun)
 	{
 		rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
 							 statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
@@ -1644,7 +1644,7 @@ _tarWriteHeader(const char *filename, const char *linktarget,
  */
 static int64
 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-			 bool sizeonly)
+			 bool dryrun)
 {
 	/* If symlink, write it as a directory anyway */
 #ifndef WIN32
@@ -1654,7 +1654,7 @@ _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
 #endif
 		statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
 
-	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
+	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, dryrun);
 }
 
 /*
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 07ed281bd6..e0210def6f 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool dryrun);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.1 (Apple Git-122.3)

0002-Refactor-some-backup-code-to-increase-reusability.-T.patchapplication/octet-stream; name=0002-Refactor-some-backup-code-to-increase-reusability.-T.patchDownload
From a8bc5cd2f3313ef768dac7cd732fd8c4f9ee6fdd Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 27 Jan 2020 17:48:10 +0500
Subject: [PATCH 2/5] Refactor some backup code to increase reusability. This
 commit adds two functions; collect_tablespaces and collect_wal_files. The
 code related to collect tablespace information is moved from
 do_pg_start_backup to collect_tablespaces function. Also, the code to collect
 wal files is moved from perform_base_backup to collect_wal_files.

This does not introduce any functional changes.
---
 src/backend/access/transam/xlog.c    | 191 ++++++++++++-----------
 src/backend/replication/basebackup.c | 217 +++++++++++++++------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 219 insertions(+), 191 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 6e09ded597..0a2eb29c75 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10306,10 +10306,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10435,93 +10431,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collect_tablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12323,3 +12233,102 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collect_tablespaces(List **tablespaces, StringInfo tblspcmapfile,
+					bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to ensure
+		 * that we can distinguish between the newline in the tablespace path
+		 * and end of line while reading tablespace_map file during archive
+		 * recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory when
+		 * it's located within PGDATA, or NULL if it's located elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created them.
+		 * Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index e90ca6184b..9583277224 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -66,6 +66,8 @@ static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *sta
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void perform_base_backup(basebackup_options *opt);
+static List *collect_wal_files(XLogRecPtr startptr, XLogRecPtr endptr,
+							   List **historyFileList);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
@@ -373,112 +375,13 @@ perform_base_backup(basebackup_options *opt)
 		 */
 		char		pathbuf[MAXPGPATH];
 		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
 		struct stat statbuf;
 		List	   *historyFileList = NIL;
 		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
 		ListCell   *lc;
 		TimeLineID	tli;
 
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
+		walFileList = collect_wal_files(startptr, endptr, &historyFileList);
 		/* Ok, we have everything we need. Send the WAL files. */
 		foreach(lc, walFileList)
 		{
@@ -611,6 +514,120 @@ perform_base_backup(basebackup_options *opt)
 
 }
 
+/*
+ * construct a list of WAL files to be included in the backup.
+ */
+static List *
+collect_wal_files(XLogRecPtr startptr, XLogRecPtr endptr, List **historyFileList)
+{
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and include
+	 * all WAL files in the range between 'startptr' and 'endptr', regardless
+	 * of the timeline the file is stamped with. If there are some spurious
+	 * WAL files belonging to timelines that don't belong in this server's
+	 * history, they will be included too. Normally there shouldn't be such
+	 * files, but if there are, there's little harm in including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			if (historyFileList)
+				*historyFileList = lappend(*historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we need
+	 * were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from oldest
+	 * to newest, to reduce the chance that a file is recycled before we get a
+	 * chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since we
+	 * are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	return walFileList;
+}
+
 /*
  * list_sort comparison function, to compare log/seg portion of WAL segment
  * filenames, ignoring the timeline portion.
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 98b033fc20..22fe35801d 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
 extern void do_pg_abort_backup(int code, Datum arg);
+extern void collect_tablespaces(List **tablespaces, StringInfo tblspcmapfile,
+								bool infotbssize, bool needtblspcmapfile);
 extern void register_persistent_abort_backup_handler(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.1 (Apple Git-122.3)

0004-Parallel-Backup-pg_basebackup.patchapplication/octet-stream; name=0004-Parallel-Backup-pg_basebackup.patchDownload
From 68e6785cfc6de4b2b3fa338f8ca9782c3161b34b Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 27 Jan 2020 18:56:21 +0500
Subject: [PATCH 4/5] Parallel Backup - pg_basebackup

Implements the replication commands added in the backend replication
system and adds support for --jobs=NUM in pg_basebackup to take a full
backup in parallel using multiple connections. The utility will collect
a list of files from the server first and then workers will copy files
(one by one) over COPY protocol. The WAL files are also copied in similar
manner.
---
 src/bin/pg_basebackup/pg_basebackup.c | 1029 +++++++++++++++++++++++--
 1 file changed, 964 insertions(+), 65 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 238b671f7a..01f4122754 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -13,6 +13,7 @@
 
 #include "postgres_fe.h"
 
+#include <pthread.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <sys/stat.h>
@@ -85,12 +86,65 @@ typedef struct UnpackTarState
 	const char *mapped_tblspc_path;
 	pgoff_t		current_len_left;
 	int			current_padding;
+	size_t		current_bytes_read;
 	FILE	   *file;
 } UnpackTarState;
 
 typedef void (*WriteDataCallback) (size_t nbytes, char *buf,
 								   void *callback_data);
 
+typedef struct BackupFile
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+
+	int			tsindex;		/* index of tsInfo this file belongs to. */
+	struct BackupFile *next;
+} BackupFile;
+
+typedef enum BackupState
+{
+	PB_FETCH_REL_LIST,
+	PB_FETCH_REL_FILES,
+	PB_FETCH_WAL_LIST,
+	PB_FETCH_WAL_FILES,
+	PB_STOP_BACKUP,
+	PB_BACKUP_COMPLETE
+} BackupState;
+
+typedef struct BackupInfo
+{
+	int			totalfiles;
+	uint64		bytes_skipped;
+	char		xlogstart[64];
+	char		xlogend[64];
+	BackupFile *files;			/* list of BackupFile pointers */
+	BackupFile *curr;			/* pointer to the file in the list */
+	BackupState backupstate;
+	bool		workersdone;
+	int			activeworkers;
+} BackupInfo;
+
+typedef struct WorkerState
+{
+	pthread_t	worker;
+	int			workerid;
+	BackupInfo *backupinfo;
+	PGconn	   *conn;
+	uint64		bytesread;
+} WorkerState;
+
+BackupInfo *backupinfo = NULL;
+WorkerState *workers = NULL;
+
+/* lock to be used for fetching file from the files list. */
+static pthread_mutex_t fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* condition to be used when the files list is filled. */
+static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -144,6 +198,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -174,10 +231,12 @@ static PQExpBuffer recoveryconfcontents = NULL;
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
+static void workers_progress_report(uint64 totalBytesRead,
+									const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveTarCopyChunk(size_t r, char *copybuf, void *callback_data);
-static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
+static int	ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf,
 										 void *callback_data);
 static void BaseBackup(void);
@@ -188,6 +247,21 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void *worker_run(void *arg);
+static void create_parallel_workers(BackupInfo *backupInfo);
+static void parallel_backup_run(BackupInfo *backupInfo);
+static void cleanup_workers(void);
+static void stop_backup(void);
+static void get_backup_filelist(PGconn *conn, BackupInfo *backupInfo);
+static void get_wal_filelist(PGconn *conn, BackupInfo *backupInfo,
+							 char *xlogstart, char *xlogend);
+static void free_filelist(BackupInfo *backupInfo);
+static int	worker_get_files(WorkerState *wstate);
+static int	receive_file(PGconn *conn, char *file, int tsIndex);
+static void create_backup_dirs(bool basetablespace, char *tablespace,
+							   char *name);
+static void create_tblspc_symlink(char *filename);
+static void writefile(char *path, char *buf);
 
 static void
 cleanup_directories_atexit(void)
@@ -239,6 +313,8 @@ cleanup_directories_atexit(void)
 static void
 disconnect_atexit(void)
 {
+	cleanup_workers();
+
 	if (conn != NULL)
 		PQfinish(conn);
 }
@@ -386,6 +462,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -732,6 +809,94 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 	}
 }
 
+/*
+ * Print a progress report of worker threads. If verbose output
+ * is enabled, also print the current file name.
+ *
+ * Progress report is written at maximum once per second, unless the
+ * force parameter is set to true.
+ */
+static void
+workers_progress_report(uint64 totalBytesRead, const char *filename, bool force)
+{
+	int			percent;
+	char		totalBytesRead_str[32];
+	char		totalsize_str[32];
+	pg_time_t	now;
+
+	if (!showprogress)
+		return;
+
+	now = time(NULL);
+	if (now == last_progress_report && !force)
+		return;					/* Max once per second */
+
+	last_progress_report = now;
+	percent = totalsize_kb ? (int) ((totalBytesRead / 1024) * 100 / totalsize_kb) : 0;
+
+	/*
+	 * Avoid overflowing past 100% or the full size. This may make the total
+	 * size number change as we approach the end of the backup (the estimate
+	 * will always be wrong if WAL is included), but that's better than having
+	 * the done column be bigger than the total.
+	 */
+	if (percent > 100)
+		percent = 100;
+	if (totalBytesRead / 1024 > totalsize_kb)
+		totalsize_kb = totalBytesRead / 1024;
+
+	/*
+	 * Separate step to keep platform-dependent format code out of
+	 * translatable strings.  And we only test for INT64_FORMAT availability
+	 * in snprintf, not fprintf.
+	 */
+	snprintf(totalBytesRead_str, sizeof(totalBytesRead_str), INT64_FORMAT,
+			 totalBytesRead / 1024);
+	snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
+
+#define VERBOSE_FILENAME_LENGTH 35
+
+	if (verbose)
+	{
+		if (!filename)
+
+			/*
+			 * No filename given, so clear the status line (used for last
+			 * call)
+			 */
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied %*s"),
+					(int) strlen(totalsize_str),
+					totalBytesRead_str, totalsize_str,
+					percent,
+					VERBOSE_FILENAME_LENGTH + 5, "");
+		else
+		{
+			bool		truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
+
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied, current file (%s%-*.*s)"),
+					(int) strlen(totalsize_str), totalBytesRead_str, totalsize_str,
+					percent,
+			/* Prefix with "..." if we do leading truncation */
+					truncate ? "..." : "",
+					truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+					truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+			/* Truncate filename at beginning if it's too long */
+					truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+				(int) strlen(totalsize_str),
+				totalBytesRead_str, totalsize_str,
+				percent);
+	}
+
+	if (isatty(fileno(stderr)))
+		fprintf(stderr, "\r");
+	else
+		fprintf(stderr, "\n");
+}
 
 /*
  * Print a progress report based on the global variables. If verbose output
@@ -748,7 +913,7 @@ progress_report(int tablespacenum, const char *filename, bool force)
 	char		totalsize_str[32];
 	pg_time_t	now;
 
-	if (!showprogress)
+	if (!showprogress || numWorkers > 1)
 		return;
 
 	now = time(NULL);
@@ -1425,7 +1590,7 @@ get_tablespace_mapping(const char *dir)
  * specified directory. If it's for another tablespace, it will be restored
  * in the original or mapped directory.
  */
-static void
+static int
 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 {
 	UnpackTarState state;
@@ -1456,13 +1621,12 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 		exit(1);
 	}
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
-
 	/*
 	 * No data is synced here, everything is done for all tablespaces at the
 	 * end.
 	 */
+
+	return state.current_bytes_read;
 }
 
 static void
@@ -1485,6 +1649,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			exit(1);
 		}
 		totaldone += 512;
+		state->current_bytes_read += 512;
 
 		state->current_len_left = read_tar_number(&copybuf[124], 12);
 
@@ -1616,6 +1781,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			fclose(state->file);
 			state->file = NULL;
 			totaldone += r;
+			state->current_bytes_read += r;
 			return;
 		}
 
@@ -1625,6 +1791,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			exit(1);
 		}
 		totaldone += r;
+		state->current_bytes_read += r;
 		progress_report(state->tablespacenum, state->filename, false);
 
 		state->current_len_left -= r;
@@ -1724,16 +1891,26 @@ BaseBackup(void)
 			fprintf(stderr, "\n");
 	}
 
-	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
-				 escaped_label,
-				 showprogress ? "PROGRESS" : "",
-				 includewal == FETCH_WAL ? "WAL" : "",
-				 fastcheckpoint ? "FAST" : "",
-				 includewal == NO_WAL ? "" : "NOWAIT",
-				 maxrate_clause ? maxrate_clause : "",
-				 format == 't' ? "TABLESPACE_MAP" : "",
-				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	if (numWorkers <= 1)
+	{
+		basebkp =
+			psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 includewal == FETCH_WAL ? "WAL" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 includewal == NO_WAL ? "" : "NOWAIT",
+					 maxrate_clause ? maxrate_clause : "",
+					 format == 't' ? "TABLESPACE_MAP" : "",
+					 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	}
+	else
+	{
+		basebkp =
+			psprintf("START_BACKUP LABEL '%s' %s",
+					 escaped_label,
+					 fastcheckpoint ? "FAST" : "");
+	}
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
@@ -1780,10 +1957,36 @@ BaseBackup(void)
 		pg_log_info("write-ahead log start point: %s on timeline %u",
 					xlogstart, starttli);
 
+	if (numWorkers > 1)
+	{
+		/*
+		 * Finish up the START_BACKUP command execution and make sure we have
+		 * CommandComplete.
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data for '%s': %s", "START_BACKUP",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		res = PQgetResult(conn);
+
+		basebkp = psprintf("LIST_TABLESPACES %s",
+						   showprogress ? "PROGRESS" : "");
+
+		if (PQsendQuery(conn, basebkp) == 0)
+		{
+			pg_log_error("could not send replication command \"%s\": %s",
+						 "LIST_TABLESPACES", PQerrorMessage(conn));
+			exit(1);
+		}
+	}
+
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1839,65 +2042,98 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
-	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
-
-	if (showprogress)
+	if (numWorkers <= 1)
 	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
-	}
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
 
-	PQclear(res);
+		if (showprogress)
+		{
+			progress_report(PQntuples(tablespacehdr), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
 
-	/*
-	 * Get the stop position
-	 */
-	res = PQgetResult(conn);
-	if (PQresultStatus(res) != PGRES_TUPLES_OK)
-	{
-		pg_log_error("could not get write-ahead log end position from server: %s",
-					 PQerrorMessage(conn));
-		exit(1);
-	}
-	if (PQntuples(res) != 1)
-	{
-		pg_log_error("no write-ahead log end position returned from server");
-		exit(1);
-	}
-	strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
-	if (verbose && includewal != NO_WAL)
-		pg_log_info("write-ahead log end point: %s", xlogend);
-	PQclear(res);
+		PQclear(res);
 
-	res = PQgetResult(conn);
-	if (PQresultStatus(res) != PGRES_COMMAND_OK)
-	{
-		const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+		/*
+		 * Get the stop position
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get write-ahead log end position from server: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) != 1)
+		{
+			pg_log_error("no write-ahead log end position returned from server");
+			exit(1);
+		}
+		strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
+		if (verbose && includewal != NO_WAL)
+			pg_log_info("write-ahead log end point: %s", xlogend);
+		PQclear(res);
 
-		if (sqlstate &&
-			strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
 		{
-			pg_log_error("checksum error occurred");
-			checksum_failure = true;
+			const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+
+			if (sqlstate &&
+				strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
+			{
+				pg_log_error("checksum error occurred");
+				checksum_failure = true;
+			}
+			else
+			{
+				pg_log_error("final receive failed: %s",
+							 PQerrorMessage(conn));
+			}
+			exit(1);
 		}
-		else
+	}
+
+	if (numWorkers > 1)
+	{
+		/*
+		 * Finish up the LIST_TABLESPACES command execution and make sure we
+		 * have CommandComplete.
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
 		{
-			pg_log_error("final receive failed: %s",
+			pg_log_error("could not get data for '%s': %s", "LIST_TABLESPACES",
 						 PQerrorMessage(conn));
+			exit(1);
 		}
-		exit(1);
+		res = PQgetResult(conn);
+
+		backupinfo = palloc0(sizeof(BackupInfo));
+		backupinfo->backupstate = PB_FETCH_REL_LIST;
+
+		/* copy starting WAL location */
+		strlcpy(backupinfo->xlogstart, xlogstart, sizeof(backupinfo->xlogstart));
+		create_parallel_workers(backupinfo);
+		parallel_backup_run(backupinfo);
+		/* copy ending WAL location */
+		strlcpy(xlogend, backupinfo->xlogend, sizeof(xlogend));
 	}
 
+	/* Write recovery contents */
+	if (format == 'p' && writerecoveryconf)
+		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
+
 	if (bgchild > 0)
 	{
 #ifndef WIN32
@@ -2052,6 +2288,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2079,7 +2316,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2220,6 +2457,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2334,6 +2574,30 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (format != 'p' && numWorkers > 1)
+	{
+		pg_log_error("parallel jobs are only supported with 'plain' format");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (maxrate > 0 && numWorkers > 1)
+	{
+		pg_log_error("--max-rate is not supported with parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2406,3 +2670,638 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+/*
+ * Worker thread function. Added for code readability.
+ */
+static void *
+worker_run(void *arg)
+{
+	WorkerState *wstate = (WorkerState *) arg;
+
+	worker_get_files(wstate);
+
+	return NULL;
+}
+
+/*
+ * Create workers and initialize worker state.
+ */
+static void
+create_parallel_workers(BackupInfo *backupinfo)
+{
+	int			status,
+				i;
+
+	workers = (WorkerState *) palloc(sizeof(WorkerState) * numWorkers);
+	backupinfo->activeworkers = 0;
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		WorkerState *worker = &workers[i];
+
+		worker->backupinfo = backupinfo;
+		worker->bytesread = 0;
+		worker->workerid = i;
+		worker->conn = GetConnection();
+		backupinfo->activeworkers++;
+
+		status = pthread_create(&worker->worker, NULL, worker_run, worker);
+		if (status != 0)
+		{
+			pg_log_error("failed to create thread: %m");
+			exit(1);
+		}
+
+		if (verbose)
+			pg_log_info("backup worker (%d) created, %d", i, status);
+	}
+}
+
+/*
+ * This is the main function that controls the worker, assign tasks and does
+ * cleanup.
+ */
+static void
+parallel_backup_run(BackupInfo *backupinfo)
+{
+	uint64_t	totalread = 0;
+
+	while (1)
+	{
+		char	   *filename = NULL;
+
+		switch (backupinfo->backupstate)
+		{
+			case PB_FETCH_REL_LIST: /* get the list of files to fetch */
+				backupinfo->backupstate = PB_FETCH_REL_FILES;
+				/* retrieve backup file list from the server. */
+				get_backup_filelist(conn, backupinfo);
+				/* unblock any workers waiting on the condition */
+				pthread_cond_broadcast(&data_ready);
+				break;
+			case PB_FETCH_REL_FILES:	/* fetch files from server */
+				if (backupinfo->activeworkers == 0)
+				{
+					backupinfo->backupstate = PB_STOP_BACKUP;
+					free_filelist(backupinfo);
+				}
+				break;
+			case PB_FETCH_WAL_LIST: /* get the list of WAL files to fetch */
+				backupinfo->backupstate = PB_FETCH_WAL_FILES;
+				get_wal_filelist(conn, backupinfo, backupinfo->xlogstart, backupinfo->xlogend);
+				/* unblock any workers waiting on the condition */
+				pthread_cond_broadcast(&data_ready);
+				break;
+			case PB_FETCH_WAL_FILES:	/* fetch WAL files from server */
+				if (backupinfo->activeworkers == 0)
+				{
+					backupinfo->backupstate = PB_BACKUP_COMPLETE;
+				}
+				break;
+			case PB_STOP_BACKUP:
+
+				/*
+				 * All relation files have been fetched, time to stop the
+				 * backup, making sure to fetch the WAL files first (if needs
+				 * be).
+				 */
+				if (includewal == FETCH_WAL)
+					backupinfo->backupstate = PB_FETCH_WAL_LIST;
+				else
+					backupinfo->backupstate = PB_BACKUP_COMPLETE;
+
+				/* get the pg_control file at last. */
+				receive_file(conn, "global/pg_control", tablespacecount - 1);
+				stop_backup();
+				break;
+			case PB_BACKUP_COMPLETE:
+
+				/*
+				 * All relation and WAL files, (if needed) have been fetched,
+				 * now we can safly stop all workers and finish up.
+				 */
+				cleanup_workers();
+				if (showprogress)
+				{
+					workers_progress_report(totalread, NULL, true);
+					if (isatty(fileno(stderr)))
+						fprintf(stderr, "\n");	/* Need to move to next line */
+				}
+
+				/* nothing more to do here */
+				return;
+				break;
+			default:
+				/* shouldn't come here. */
+				pg_log_error("unexpected backup state: %d",
+							 backupinfo->backupstate);
+				exit(1);
+				break;
+		}
+
+		/* update and report progress */
+		totalread = 0;
+		for (int i = 0; i < numWorkers; i++)
+		{
+			WorkerState *worker = &workers[i];
+
+			totalread += worker->bytesread;
+		}
+		totalread += backupinfo->bytes_skipped;
+
+		if (backupinfo->curr != NULL)
+			filename = backupinfo->curr->path;
+
+		workers_progress_report(totalread, filename, false);
+		pg_usleep(100000);
+	}
+}
+
+/*
+ * Wait for the workers to complete the work and free connections.
+ */
+static void
+cleanup_workers(void)
+{
+	/* either non parallel backup */
+	if (!backupinfo)
+		return;
+	/* workers have already been stopped and cleanup has been done. */
+	if (backupinfo->workersdone)
+		return;
+
+	backupinfo->workersdone = true;
+	/* wakeup any workers waiting on the condition */
+	pthread_cond_broadcast(&data_ready);
+
+	for (int i = 0; i < numWorkers; i++)
+	{
+		pthread_join(workers[i].worker, NULL);
+		PQfinish(workers[i].conn);
+	}
+	free_filelist(backupinfo);
+}
+
+/*
+ * Take the system out of backup mode, also adds the backup_label file in
+ * the backup.
+ */
+static void
+stop_backup(void)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP %s",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * Get the stop position
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get write-ahead log end position from server: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) != 1)
+	{
+		pg_log_error("no write-ahead log end position returned from server");
+		exit(1);
+	}
+
+	/* retrieve the end wal location. */
+	strlcpy(backupinfo->xlogend, PQgetvalue(res, 0, 0),
+			sizeof(backupinfo->xlogend));
+
+	/* retrieve the backup_label file contents and write them to the backup */
+	writefile("backup_label", PQgetvalue(res, 0, 2));
+
+	PQclear(res);
+
+	/*
+	 * Finish up the Stop command execution and make sure we have
+	 * CommandComplete and ReadyForQuery response.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+
+	if (verbose && includewal != NO_WAL)
+		pg_log_info("write-ahead log end point: %s", backupinfo->xlogend);
+}
+
+/*
+ * Retrieves the list of files available in $PGDATA from the server.
+ */
+static void
+get_backup_filelist(PGconn *conn, BackupInfo *backupInfo)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	for (int i = 0; i < tablespacecount; i++)
+	{
+		bool		basetablespace;
+		char	   *tablespace;
+		int			numFiles;
+
+		/*
+		 * Query server to fetch the file list for given tablespace name. If
+		 * the tablespace name is empty, it will fetch files list of 'base'
+		 * tablespace.
+		 */
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tablespace = PQgetvalue(tablespacehdr, i, 1);
+
+		basebkp = psprintf("LIST_FILES '%s'",
+						   basetablespace ? "" : tablespace);
+		if (PQsendQuery(conn, basebkp) == 0)
+		{
+			pg_log_error("could not send replication command \"%s\": %s",
+						 "LIST_FILES", PQerrorMessage(conn));
+			exit(1);
+		}
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not list backup files: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		numFiles = PQntuples(res);
+		for (int j = 0; j < numFiles; j++)
+		{
+			BackupFile *file;
+			char	   *path = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+			{
+				/*
+				 * directory entries are skipped. however, a tar header size
+				 * was included for them in totalsize_kb, so we need to add it
+				 * for progress reporting purpose.
+				 */
+				backupInfo->bytes_skipped += 512;
+				create_backup_dirs(basetablespace, tablespace, path);
+				continue;
+			}
+
+			if (format == 'p' && type == 'l')
+			{
+				/*
+				 * symlink entries are skipped. however, a tar header size was
+				 * included for them in totalsize_kb, so we need to add it for
+				 * progress reporting purpose.
+				 */
+				backupInfo->bytes_skipped += 512;
+				create_tblspc_symlink(path);
+				continue;
+			}
+
+			file = (BackupFile *) palloc(sizeof(BackupFile));
+			strlcpy(file->path, path, MAXPGPATH);
+			file->type = type;
+			file->size = size;
+			file->mtime = mtime;
+			file->tsindex = i;
+
+			/* add to the files list */
+			backupInfo->totalfiles++;
+			if (backupInfo->files == NULL)
+				backupInfo->curr = backupInfo->files = file;
+			else
+			{
+				backupInfo->curr->next = file;
+				backupInfo->curr = backupInfo->curr->next;
+			}
+		}
+
+		PQclear(res);
+
+		/*
+		 * Finish up the LIST_FILES command execution and make sure we have
+		 * CommandComplete.
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data for '%s': %s", "LIST_FILES",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		res = PQgetResult(conn);
+	}
+
+	/* point curr to the head of list. */
+	backupInfo->curr = backupInfo->files;
+}
+
+/*
+ * Retrieve WAL file list from the server based on the starting wal location
+ * and ending wal location.
+ */
+static void
+get_wal_filelist(PGconn *conn, BackupInfo *backupInfo, char *xlogstart, char *xlogend)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+	int			numWals;
+
+	basebkp = psprintf("LIST_WAL_FILES START_WAL_LOCATION '%s' END_WAL_LOCATION '%s'",
+					   xlogstart, xlogend);
+
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "LIST_FILES", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not list wal files: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	numWals = PQntuples(res);
+	for (int i = 0; i < numWals; i++)
+	{
+		BackupFile *file = (BackupFile *) palloc0(sizeof(BackupFile));
+
+		if (backupInfo->files == NULL)
+		{
+			backupInfo->curr = backupInfo->files = file;
+		}
+		else
+		{
+			backupInfo->curr->next = file;
+			backupInfo->curr = file;
+		}
+
+		strlcpy(file->path, PQgetvalue(res, i, 0), MAXPGPATH);
+		file->tsindex = tablespacecount - 1;
+		backupInfo->totalfiles++;
+	}
+
+	/*
+	 * Finish up the LIST_WAL_FILES command execution and make sure we have
+	 * CommandComplete.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data for '%s': %s", "LIST_WAL_FILES",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+
+	/* point curr to the head of list. */
+	backupInfo->curr = backupInfo->files;
+}
+
+/* free files list */
+static void
+free_filelist(BackupInfo *backupInfo)
+{
+	/* free files list */
+	if (backupInfo->files != NULL)
+	{
+		backupInfo->curr = backupInfo->files;
+		while (backupInfo->curr != NULL)
+		{
+			BackupFile *file = backupInfo->curr;
+
+			backupInfo->curr = file->next;
+
+			pfree(file);
+		}
+
+		backupInfo->files = NULL;
+		backupInfo->totalfiles = 0;
+	}
+}
+
+/*
+ * Worker function to process and retrieve the files from the server. If the
+ * files list is empty, it will wait for it to be filled. Otherwise picks the
+ * next file in the list.
+ */
+static int
+worker_get_files(WorkerState *wstate)
+{
+	BackupFile *fetchfile = NULL;
+	BackupInfo *backupinfo = wstate->backupinfo;
+
+	while (!backupinfo->workersdone)
+	{
+		pthread_mutex_lock(&fetch_mutex);
+		if (backupinfo->curr == NULL)
+		{
+			/*
+			 * Wait until there is data available in the list to process.
+			 * pthread_cond_wait call unlocks the already locked mutex during
+			 * the wait state. When the condition is true (a signal is
+			 * raised), one of the competing threads acquires the mutex.
+			 */
+			backupinfo->activeworkers--;
+			pthread_cond_wait(&data_ready, &fetch_mutex);
+			backupinfo->activeworkers++;
+		}
+
+		fetchfile = backupinfo->curr;
+		if (fetchfile != NULL)
+		{
+			backupinfo->totalfiles--;
+			backupinfo->curr = fetchfile->next;
+		}
+		pthread_mutex_unlock(&fetch_mutex);
+
+		if (fetchfile != NULL)
+		{
+			wstate->bytesread +=
+				receive_file(wstate->conn, fetchfile->path, fetchfile->tsindex);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function fetches the requested file from the server.
+ */
+static int
+receive_file(PGconn *conn, char *file, int tsIndex)
+{
+	PGresult   *res = NULL;
+	int			bytesread;
+	PQExpBuffer buf = createPQExpBuffer();
+
+	/*
+	 * Fetch a single file from the server. To fetch the file, build a query
+	 * in form of:
+	 *
+	 * SEND_FILES ('base/1/1245/32683') [options]
+	 */
+	appendPQExpBuffer(buf, "SEND_FILES ( '%s' )", file);
+
+	/* add options */
+	appendPQExpBuffer(buf, " START_WAL_LOCATION '%s' %s",
+					  backupinfo->xlogstart,
+					  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	if (!conn)
+		return 1;
+
+	if (PQsendQuery(conn, buf->data) == 0)
+	{
+		pg_log_error("could not send files list \"%s\"",
+					 PQerrorMessage(conn));
+		return 1;
+	}
+
+	destroyPQExpBuffer(buf);
+
+	/* process file contents, also count bytesRead for progress */
+	bytesread = ReceiveAndUnpackTarFile(conn, tablespacehdr, tsIndex);
+
+	PQclear(res);
+
+	/*
+	 * Finish up the SEND_FILES command execution and make sure we have
+	 * CommandComplete.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data for '%s': %s", "SEND_FILES",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+	return bytesread;
+}
+
+/*
+ * Create backup directories while taking care of tablespace path. If tablespace
+ * mapping (with -T) is given then the directory will be created on the mapped
+ * path.
+ */
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char		dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+/*
+ * Create a symlink in pg_tblspc and apply any tablespace mapping given on
+ * the command line (--tablespace-mapping).
+ */
+static void
+create_tblspc_symlink(char *filename)
+{
+	int			i;
+
+	for (i = 0; i < tablespacecount; i++)
+	{
+		char	   *tsoid = PQgetvalue(tablespacehdr, i, 0);
+
+		if (strstr(filename, tsoid) != NULL)
+		{
+			char	   *linkloc = psprintf("%s/%s", basedir, filename);
+			const char *mapped_tblspc_path = get_tablespace_mapping(PQgetvalue(tablespacehdr, i, 1));
+
+#ifdef HAVE_SYMLINK
+			if (symlink(mapped_tblspc_path, linkloc) != 0)
+			{
+				pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
+							 linkloc, mapped_tblspc_path);
+				exit(1);
+			}
+#else
+			pg_log_error("symlinks are not supported on this platform");
+			exit(1);
+#endif
+			free(linkloc);
+			break;
+		}
+	}
+}
+
+/*
+ * General function for writing to a file; creates one if it doesn't exist
+ */
+static void
+writefile(char *path, char *buf)
+{
+	FILE	   *f;
+	char		pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
-- 
2.21.1 (Apple Git-122.3)

0005-parallel-backup-testcase.patchapplication/octet-stream; name=0005-parallel-backup-testcase.patchDownload
From b659afb30307702886b0663ebb958d0ea4371c01 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 5/5] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 527 ++++++++++++++++++
 1 file changed, 527 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 0000000000..4ec4c1e0f6
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,527 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 95;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+#	# Create a temporary directory in the system location and symlink it
+#	# to our physical temp location.  That way we can use shorter names
+#	# for the tablespace directories, which hopefully won't run afoul of
+#	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+my $file;
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.1 (Apple Git-122.3)

0003-Parallel-Backup-Backend-Replication-commands.patchapplication/octet-stream; name=0003-Parallel-Backup-Backend-Replication-commands.patchDownload
From e5998a955fe224babced5f5f5c5caf122872165d Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 27 Jan 2020 18:32:42 +0500
Subject: [PATCH 3/5] Parallel Backup - Backend Replication commands

This feature adds following replication commands to the backend replication
system, to help facilitate taking a full backup in parallel using multiple
connections.

	- START_BACKUP [LABEL '<label>'] [FAST]
	This command instructs the server to get prepared for performing an
	online backup.

	- STOP_BACKUP [NOWAIT]
	This command instructs the server that online backup is finished. It
	will bring the system out of backup mode.

	- LIST_TABLESPACES [PROGRESS]
	This command instructs the server to return a list of tablespaces.

	- LIST_FILES [TABLESPACE]
	This command instructs the server to return a list of files for a
	given tablespace, base tablespace if TABLESPACE is empty.

	- LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
	This command instructs the server to return a list WAL files between
	the given locations.

	- SEND_FILES '(' FILE, FILE... ')' [START_WAL_LOCATION 'X/X']
			[NOVERIFY_CHECKSUMS]
	Instructs the server to send the contents of the requested FILE(s).
---
 src/backend/access/transam/xlog.c      |   4 +-
 src/backend/replication/basebackup.c   | 529 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    | 265 +++++++++++--
 src/backend/replication/repl_scanner.l |   8 +
 src/include/nodes/replnodes.h          |  12 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 751 insertions(+), 69 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0a2eb29c75..fc294a61a9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -11078,7 +11078,7 @@ do_pg_abort_backup(int code, Datum arg)
 
 	if (emit_warning)
 		ereport(WARNING,
-				(errmsg("aborting backup due to backend exiting before pg_stop_back up was called")));
+				(errmsg("aborting backup due to backend exiting while a non-exclusive backup is in progress")));
 }
 
 /*
@@ -12310,7 +12310,7 @@ collect_tablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 9583277224..90f96bf20d 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -38,6 +38,8 @@
 #include "storage/ipc.h"
 #include "storage/reinit.h"
 #include "utils/builtins.h"
+#include "utils/memutils.h"
+#include "utils/pg_lsn.h"
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
@@ -51,11 +53,22 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	XLogRecPtr	startwallocation;
+	XLogRecPtr	endwallocation;
+	char	   *tablespace;
 } basebackup_options;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	size_t		size;
+	time_t		mtime;
+} BackupFile;
+
 
 static int64 sendDir(const char *path, int basepathlen, bool dryrun,
-					 List *tablespaces, bool sendtblspclinks);
+					 List *tablespaces, bool sendtblspclinks, List **filelist);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -69,11 +82,27 @@ static void perform_base_backup(basebackup_options *opt);
 static List *collect_wal_files(XLogRecPtr startptr, XLogRecPtr endptr,
 							   List **historyFileList);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
-static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
+static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli, StringInfo label);
+static void SendFilesHeader(List *files);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void start_backup(basebackup_options *opt);
+static void stop_backup(basebackup_options *opt);
+static void list_tablespaces(basebackup_options *opt);
+static void list_files(basebackup_options *opt);
+static void list_wal_files(basebackup_options *opt);
+static void send_files(basebackup_options *opt, List *filenames,
+					   bool missing_ok);
+static void add_to_filelist(List **filelist, char *path, char type,
+							size_t size, time_t mtime);
+
+/*
+ * Store label file during non-exclusive backups.
+ */
+static StringInfo label_file;
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -260,7 +289,7 @@ perform_base_backup(basebackup_options *opt)
 		ListCell   *lc;
 		tablespaceinfo *ti;
 
-		SendXlogRecPtrResult(startptr, starttli);
+		SendXlogRecPtrResult(startptr, starttli, NULL);
 
 		/*
 		 * Calculate the relative path of temporary statistics directory in
@@ -276,7 +305,7 @@ perform_base_backup(basebackup_options *opt)
 
 		/* Add a node for the base directory at the end */
 		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
 		tablespaces = lappend(tablespaces, ti);
 
 		/* Send tablespace header */
@@ -332,10 +361,10 @@ perform_base_backup(basebackup_options *opt)
 				if (tblspc_map_file && opt->sendtblspcmapfile)
 				{
 					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-					sendDir(".", 1, false, tablespaces, false);
+					sendDir(".", 1, false, tablespaces, false, NULL);
 				}
 				else
-					sendDir(".", 1, false, tablespaces, true);
+					sendDir(".", 1, false, tablespaces, true, NULL);
 
 				/* ... and pg_control after everything else. */
 				if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -346,7 +375,7 @@ perform_base_backup(basebackup_options *opt)
 				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 			}
 			else
-				sendTablespace(ti->path, false);
+				sendTablespace(ti->path, false, NULL);
 
 			/*
 			 * If we're including WAL, and this is the main data directory we
@@ -499,7 +528,7 @@ perform_base_backup(basebackup_options *opt)
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
 	}
-	SendXlogRecPtrResult(endptr, endtli);
+	SendXlogRecPtrResult(endptr, endtli, NULL);
 
 	if (total_checksum_failures)
 	{
@@ -656,6 +685,9 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_startwallocation = false;
+	bool		o_endwallocation = false;
+	bool		o_tablespace = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -744,12 +776,47 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "start_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *startwallocation;
+
+			if (o_startwallocation)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			startwallocation = strVal(defel->arg);
+			opt->startwallocation = pg_lsn_in_internal(startwallocation, &have_error);
+			o_startwallocation = true;
+		}
+		else if (strcmp(defel->defname, "end_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *endwallocation;
+
+			if (o_endwallocation)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			endwallocation = strVal(defel->arg);
+			opt->endwallocation = pg_lsn_in_internal(endwallocation, &have_error);
+			o_endwallocation = true;
+		}
+		else if (strcmp(defel->defname, "tablespace") == 0)
+		{
+			if (o_tablespace)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+			opt->tablespace = strVal(defel->arg);
+			o_tablespace = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
 	}
-	if (opt->label == NULL)
-		opt->label = "base backup";
 }
 
 
@@ -767,6 +834,15 @@ SendBaseBackup(BaseBackupCmd *cmd)
 
 	parse_basebackup_options(cmd->options, &opt);
 
+	/* default value for label, if not specified. */
+	if (opt.label == NULL)
+	{
+		if (cmd->cmdtag == BASE_BACKUP)
+			opt.label = "base backup";
+		else
+			opt.label = "start backup";
+	}
+
 	WalSndSetState(WALSNDSTATE_BACKUP);
 
 	if (update_process_title)
@@ -778,7 +854,34 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg, false);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			start_backup(&opt);
+			break;
+		case LIST_TABLESPACES:
+			list_tablespaces(&opt);
+			break;
+		case LIST_FILES:
+			list_files(&opt);
+			break;
+		case SEND_FILES:
+			send_files(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			stop_backup(&opt);
+			break;
+		case LIST_WAL_FILES:
+			list_wal_files(&opt);
+			break;
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -866,18 +969,18 @@ SendBackupHeader(List *tablespaces)
 }
 
 /*
- * Send a single resultset containing just a single
- * XLogRecPtr record (in text format)
+ * Send a single resultset containing XLogRecPtr record (in text format)
+ * TimelineID and backup label.
  */
 static void
-SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
+SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli, StringInfo label)
 {
 	StringInfoData buf;
 	char		str[MAXFNAMELEN];
 	Size		len;
 
 	pq_beginmessage(&buf, 'T'); /* RowDescription */
-	pq_sendint16(&buf, 2);		/* 2 fields */
+	pq_sendint16(&buf, 3);		/* 3 fields */
 
 	/* Field headers */
 	pq_sendstring(&buf, "recptr");
@@ -900,11 +1003,19 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_sendint16(&buf, -1);
 	pq_sendint32(&buf, 0);
 	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
 	pq_endmessage(&buf);
 
 	/* Data row */
 	pq_beginmessage(&buf, 'D');
-	pq_sendint16(&buf, 2);		/* number of columns */
+	pq_sendint16(&buf, 3);		/* number of columns */
 
 	len = snprintf(str, sizeof(str),
 				   "%X/%X", (uint32) (ptr >> 32), (uint32) ptr);
@@ -915,12 +1026,109 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_sendint32(&buf, len);
 	pq_sendbytes(&buf, str, len);
 
+	if (label)
+	{
+		len = label->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, label->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* NULL */
+	}
+
 	pq_endmessage(&buf);
 
 	/* Send a CommandComplete message */
 	pq_puttextmessage('C', "SELECT");
 }
 
+
+/*
+ * Sends the resultset containing filename, type (where type can be f' for
+ * regular, 'd' for directory, 'l' for link), file size and modification time).
+ */
+static void
+SendFilesHeader(List *files)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+
+	/* Construct and send the list of files */
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 4);		/* n field */
+
+	/* First field - file name */
+	pq_sendstring(&buf, "path");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, TEXTOID);
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	/* Second field - is_dir */
+	pq_sendstring(&buf, "type");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, CHAROID);
+	pq_sendint16(&buf, 1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	/* Third field - size */
+	pq_sendstring(&buf, "size");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, INT8OID);
+	pq_sendint16(&buf, 8);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	/* Fourth field - mtime */
+	pq_sendstring(&buf, "mtime");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, INT8OID);
+	pq_sendint16(&buf, 8);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	foreach(lc, files)
+	{
+		BackupFile *file = (BackupFile *) lfirst(lc);
+		Size		len;
+
+		/* Send one datarow message */
+		pq_beginmessage(&buf, 'D');
+		pq_sendint16(&buf, 4);	/* number of columns */
+
+		/* send path */
+		len = strlen(file->path);
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, file->path, len);
+
+		/* send type */
+		pq_sendint32(&buf, 1);
+		pq_sendbyte(&buf, file->type);
+
+		/* send size */
+		send_int8_string(&buf, file->size);
+
+		/* send mtime */
+		send_int8_string(&buf, file->mtime);
+
+		pq_endmessage(&buf);
+	}
+
+	list_free(files);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -972,7 +1180,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool dryrun)
+sendTablespace(char *path, bool dryrun, List **filelist)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -1001,11 +1209,11 @@ sendTablespace(char *path, bool dryrun)
 		return 0;
 	}
 
+	add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   dryrun);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true, filelist);
 
 	return size;
 }
@@ -1024,7 +1232,7 @@ sendTablespace(char *path, bool dryrun)
  */
 static int64
 sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
-		bool sendtblspclinks)
+		bool sendtblspclinks, List **filelist)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -1178,6 +1386,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
@@ -1194,6 +1404,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
@@ -1215,6 +1427,10 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									dryrun);
 
+			add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
+			add_to_filelist(filelist, "./pg_wal/archive_status", 'd', -1,
+							statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -1244,6 +1460,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			add_to_filelist(filelist, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, dryrun);
 #else
@@ -1270,6 +1487,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									dryrun);
+			add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1300,13 +1518,15 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks, filelist);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!dryrun)
+			add_to_filelist(filelist, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!dryrun && filelist == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? atooid(lastDir + 1) : InvalidOid);
 
@@ -1747,3 +1967,268 @@ throttle(size_t increment)
 	 */
 	throttled_last = GetCurrentTimestamp();
 }
+
+/*
+ * start_backup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+start_backup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	tblspc_map_file;
+	MemoryContext oldcontext;
+
+	/* Label file need to be long-lived, since its read in stop_backup. */
+	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+	label_file = makeStringInfo();
+	MemoryContextSwitchTo(oldcontext);
+
+	/*
+	 * tablespace map file is not used, but since this argument is required by
+	 * do_pg_start_backup, we have to provide it here.
+	 */
+	tblspc_map_file = makeStringInfo();
+
+	register_persistent_abort_backup_handler();
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  label_file, NULL, tblspc_map_file, false, false);
+
+	/* send startptr and starttli to frontend */
+	SendXlogRecPtrResult(startptr, starttli, NULL);
+
+	/* free tablspace map buffer. */
+	pfree(tblspc_map_file->data);
+	pfree(tblspc_map_file);
+}
+
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */
+static void
+stop_backup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+
+	if (get_backup_status() != SESSION_BACKUP_NON_EXCLUSIVE)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("non-exclusive backup is not in progress")));
+
+	/*
+	 * Stop the non-exclusive backup. Return a copy of the backup label so it
+	 * can be written to disk by the caller.
+	 */
+	endptr = do_pg_stop_backup(label_file->data, !opt->nowait, &endtli);
+	SendXlogRecPtrResult(endptr, endtli, label_file);
+
+	/* Free structures allocated in TopMemoryContext */
+	pfree(label_file->data);
+	pfree(label_file);
+	label_file = NULL;
+}
+
+/*
+ * list_tablespaces() - sends a list of tablespace entries
+ */
+static void
+list_tablespaces(basebackup_options *opt)
+{
+	StringInfo	tblspc_map_file;
+	List	   *tablespaces = NIL;
+	tablespaceinfo *ti;
+
+	tblspc_map_file = makeStringInfo();
+	collect_tablespaces(&tablespaces, tblspc_map_file, opt->progress, false);
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
+	tablespaces = lappend(tablespaces, ti);
+
+	SendBackupHeader(tablespaces);
+	list_free(tablespaces);
+}
+
+/*
+ * list_files() - sends a list of files available in given tablespace.
+ */
+static void
+list_files(basebackup_options *opt)
+{
+	List	   *files = NIL;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	/*
+	 * Calculate the relative path of temporary statistics directory in order
+	 * to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
+
+	if (strlen(opt->tablespace) > 0)
+		sendTablespace(opt->tablespace, true, &files);
+	else
+		sendDir(".", 1, true, NIL, true, &files);
+
+	SendFilesHeader(files);
+}
+
+/*
+ * list_wal_files() - sends a list of WAL files between start wal location and
+ * end wal location.
+ */
+static void
+list_wal_files(basebackup_options *opt)
+{
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	List	   *files = NIL;
+	ListCell   *lc;
+
+	walFileList = collect_wal_files(opt->startwallocation, opt->endwallocation,
+									&historyFileList);
+	foreach(lc, walFileList)
+	{
+		char		pathbuf[MAXPGPATH];
+		char	   *walFileName = (char *) lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		add_to_filelist(&files, pathbuf, 'f', wal_segment_size, 0);
+	}
+
+	SendFilesHeader(files);
+}
+
+/*
+ * send_files() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol. It does only entertains the regular files and any other kind such
+ * as directories or symlink etc will be ignored.
+ */
+static void
+send_files(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	int			basepathlen = 0;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Disable throttling. */
+	throttling_counter = -1;
+
+	/* set backup start location. */
+	startptr = opt->startwallocation;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (is_absolute_path(pathbuf))
+		{
+			char	   *basepath;
+
+			/*
+			 * 'pathbuf' points to the tablespace location, but we only want
+			 * to include the version directory in it that belongs to us.
+			 */
+			basepath = strstr(pathbuf, TABLESPACE_VERSION_DIRECTORY);
+			if (basepath)
+				basepathlen = basepath - pathbuf - 1;
+		}
+		else if (pathbuf[0] == '.' && pathbuf[1] == '/')
+			basepathlen = 2;
+		else
+			basepathlen = 0;
+
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/*
+		 * Only entertain requests for regular file, skip any directories or
+		 * special files.
+		 */
+		if (S_ISREG(statbuf.st_mode))
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen, &statbuf, true, InvalidOid);
+		}
+		else
+			ereport(WARNING,
+					(errmsg("skipping special file or directory \"%s\"", pathbuf)));
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report total checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+/*
+ * Construct a BackupFile entry and add to the list.
+ */
+static void
+add_to_filelist(List **filelist, char *path, char type, size_t size,
+				time_t mtime)
+{
+	BackupFile *file;
+
+	if (filelist)
+	{
+		file = (BackupFile *) palloc(sizeof(BackupFile));
+		strlcpy(file->path, path, sizeof(file->path));
+		file->type = type;
+		file->size = size;
+		file->mtime = mtime;
+
+		*filelist = lappend(*filelist, file);
+	}
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index 2d96567409..f79e1a504f 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,13 +87,28 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_LIST_TABLESPACES
+%token K_LIST_FILES
+%token K_SEND_FILES
+%token K_STOP_BACKUP
+%token K_LIST_WAL_FILES
+%token K_START_WAL_LOCATION
+%token K_END_WAL_LOCATION
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
 				create_replication_slot drop_replication_slot identify_system
 				timeline_history show sql_cmd
-%type <list>	base_backup_opt_list
-%type <defelt>	base_backup_opt
+%type <list>	base_backup_opt_list start_backup_opt_list stop_backup_opt_list
+				list_tablespace_opt_list list_files_opt_list
+				list_wal_files_opt_list send_backup_files_opt_list
+				backup_files backup_files_list
+%type <defelt>	base_backup_opt backup_opt_label backup_opt_progress
+				backup_opt_fast backup_opt_wal backup_opt_nowait
+				backup_opt_maxrate backup_opt_tsmap backup_opt_chksum
+				backup_opt_start_wal_loc backup_opt_end_wal_loc
+				backup_opt_tablespace start_backup_opt send_backup_files_opt
 %type <uintval>	opt_timeline
 %type <list>	plugin_options plugin_opt_list
 %type <defelt>	plugin_opt_elem
@@ -153,69 +168,231 @@ var_name:	IDENT	{ $$ = $1; }
 				{ $$ = psprintf("%s.%s", $1, $3); }
 		;
 
-/*
- * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
- * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS]
- */
 base_backup:
+			/*
+			 * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
+			 * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS]
+			 */
 			K_BASE_BACKUP base_backup_opt_list
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
 					$$ = (Node *) cmd;
 				}
-			;
-
-base_backup_opt_list:
-			base_backup_opt_list base_backup_opt
-				{ $$ = lappend($1, $2); }
-			| /* EMPTY */
-				{ $$ = NIL; }
-			;
-
-base_backup_opt:
-			K_LABEL SCONST
-				{
-				  $$ = makeDefElem("label",
-								   (Node *)makeString($2), -1);
-				}
-			| K_PROGRESS
+			 /* START_BACKUP [LABEL '<label>'] [FAST] */
+			| K_START_BACKUP start_backup_opt_list
 				{
-				  $$ = makeDefElem("progress",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_FAST
-				{
-				  $$ = makeDefElem("fast",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
 				}
-			| K_WAL
+			/* STOP_BACKUP [NOWAIT] */
+			| K_STOP_BACKUP stop_backup_opt_list
 				{
-				  $$ = makeDefElem("wal",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
+					$$ = (Node *) cmd;
 				}
-			| K_NOWAIT
+			/* LIST_TABLESPACES [PROGRESS] */
+			| K_LIST_TABLESPACES list_tablespace_opt_list
 				{
-				  $$ = makeDefElem("nowait",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = LIST_TABLESPACES;
+					$$ = (Node *) cmd;
 				}
-			| K_MAX_RATE UCONST
+			/* LIST_FILES [TABLESPACE] */
+			| K_LIST_FILES list_files_opt_list
 				{
-				  $$ = makeDefElem("max_rate",
-								   (Node *)makeInteger($2), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = LIST_FILES;
+					$$ = (Node *) cmd;
 				}
-			| K_TABLESPACE_MAP
+			/* LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X'] */
+			| K_LIST_WAL_FILES list_wal_files_opt_list
 				{
-				  $$ = makeDefElem("tablespace_map",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = LIST_WAL_FILES;
+					$$ = (Node *) cmd;
 				}
-			| K_NOVERIFY_CHECKSUMS
+			/*
+			 * SEND_FILES '(' 'FILE' [, ...] ')' [START_WAL_LOCATION 'X/X']
+			 *		[NOVERIFY_CHECKSUMS]
+			 */
+			| K_SEND_FILES backup_files send_backup_files_opt_list
 				{
-				  $$ = makeDefElem("noverify_checksums",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_FILES;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
 				}
 			;
 
+base_backup_opt_list:
+			base_backup_opt_list base_backup_opt
+				{ $$ = lappend($1, $2); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+base_backup_opt:
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_progress	{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			| backup_opt_wal 		{ $$ = $1; }
+			| backup_opt_nowait		{ $$ = $1; }
+			| backup_opt_maxrate	{ $$ = $1; }
+			| backup_opt_tsmap		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			;
+
+start_backup_opt_list:
+			start_backup_opt_list start_backup_opt
+				{ $$ = lappend($1, $2); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+start_backup_opt:
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			;
+
+stop_backup_opt_list:
+			backup_opt_nowait
+				{ $$ = list_make1($1); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+list_tablespace_opt_list:
+			backup_opt_progress
+				{ $$ = list_make1($1); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+list_files_opt_list:
+			backup_opt_tablespace
+				{ $$ = list_make1($1); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+list_wal_files_opt_list:
+			backup_opt_start_wal_loc backup_opt_end_wal_loc
+				{ $$ = list_make2($1, $2); }
+			;
+
+send_backup_files_opt_list:
+			send_backup_files_opt_list send_backup_files_opt
+				{ $$ = lappend($1, $2); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{ $$ = $2; }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			SCONST
+				{ $$ = list_make1(makeString($1)); }
+			| backup_files_list ',' SCONST
+				{ $$ = lappend($1, makeString($3)); }
+			;
+
+send_backup_files_opt:
+			backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_start_wal_loc	{ $$ = $1; }
+			;
+
+backup_opt_label:
+	K_LABEL SCONST
+	{
+	  $$ = makeDefElem("label",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_progress:
+	K_PROGRESS
+	{
+	  $$ = makeDefElem("progress",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_fast:
+	K_FAST
+	{
+	  $$ = makeDefElem("fast",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal:
+	K_WAL
+	{
+	  $$ = makeDefElem("wal",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_nowait:
+	K_NOWAIT
+	{
+	  $$ = makeDefElem("nowait",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_maxrate:
+	K_MAX_RATE UCONST
+	{
+	  $$ = makeDefElem("max_rate",
+					   (Node *)makeInteger($2), -1);
+	};
+
+backup_opt_tsmap:
+	K_TABLESPACE_MAP
+	{
+	  $$ = makeDefElem("tablespace_map",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_chksum:
+	K_NOVERIFY_CHECKSUMS
+	{
+	  $$ = makeDefElem("noverify_checksums",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_start_wal_loc:
+	K_START_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("start_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_end_wal_loc:
+	K_END_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("end_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_tablespace:
+	SCONST
+	{
+		$$ = makeDefElem("tablespace", //tblspcname?
+						 (Node *)makeString($1), -1);
+	};
+
 create_replication_slot:
 			/* CREATE_REPLICATION_SLOT slot TEMPORARY PHYSICAL RESERVE_WAL */
 			K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL create_slot_opt_list
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 14c9a1e798..faa00cfd0e 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,14 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+LIST_FILES			{ return K_LIST_FILES; }
+LIST_TABLESPACES	{ return K_LIST_TABLESPACES; }
+SEND_FILES			{ return K_SEND_FILES; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+LIST_WAL_FILES		{ return K_LIST_WAL_FILES; }
+START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
+END_WAL_LOCATION	{ return K_END_WAL_LOCATION; }
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 5456141a8a..c046ea39ae 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,16 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	LIST_TABLESPACES,
+	LIST_FILES,
+	LIST_WAL_FILES,
+	SEND_FILES,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +52,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index e0210def6f..3bc85d4c3e 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool dryrun);
+extern int64 sendTablespace(char *path, bool dryrun, List **filelist);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.1 (Apple Git-122.3)

#43Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Asif Rehman (#42)
Re: WIP/PoC for parallel backup

Hi Asif,

On Thu, Jan 30, 2020 at 7:10 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Here are the the updated patches, taking care of the issues pointed
earlier. This patch adds the following commands (with specified option):

START_BACKUP [LABEL '<label>'] [FAST]
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILES '(' FILE, FILE... ')' [START_WAL_LOCATION 'X/X']
[NOVERIFY_CHECKSUMS]

Parallel backup is not making any use of tablespace map, so I have
removed that option from the above commands. There is a patch pending
to remove the exclusive backup; we can further refactor the
do_pg_start_backup
function at that time, to remove the tablespace information and move the
creation of tablespace_map file to the client.

I have disabled the maxrate option for parallel backup. I intend to send
out a separate patch for it. Robert previously suggested to implement
throttling on the client-side. I found the original email thread [1]
where throttling was proposed and added to the server. In that thread,
it was originally implemented on the client-side, but per many suggestions,
it was moved to server-side.

So, I have a few suggestions on how we can implement this:

1- have another option for pg_basebackup (i.e. per-worker-maxrate) where
the user could choose the bandwidth allocation for each worker. This
approach
can be implemented on the client-side as well as on the server-side.

2- have the maxrate, be divided among workers equally at first. and the
let the main thread keep adjusting it whenever one of the workers finishes.
I believe this would only be possible if we handle throttling on the
client.
Also, as I understand it, implementing this will introduce additional mutex
for handling of bandwidth consumption data so that rate may be adjusted
according to data received by threads.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

The latest changes look good to me. However, the patch set is missing the
documentation.
Please add those.

Thanks

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

#44Asif Rehman
asifr.rehman@gmail.com
In reply to: Jeevan Chalke (#43)
1 attachment(s)
Re: WIP/PoC for parallel backup

Thanks Jeevan. Here is the documentation patch.

On Mon, Feb 10, 2020 at 6:49 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

On Thu, Jan 30, 2020 at 7:10 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Here are the the updated patches, taking care of the issues pointed
earlier. This patch adds the following commands (with specified option):

START_BACKUP [LABEL '<label>'] [FAST]
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILES '(' FILE, FILE... ')' [START_WAL_LOCATION 'X/X']
[NOVERIFY_CHECKSUMS]

Parallel backup is not making any use of tablespace map, so I have
removed that option from the above commands. There is a patch pending
to remove the exclusive backup; we can further refactor the
do_pg_start_backup
function at that time, to remove the tablespace information and move the
creation of tablespace_map file to the client.

I have disabled the maxrate option for parallel backup. I intend to send
out a separate patch for it. Robert previously suggested to implement
throttling on the client-side. I found the original email thread [1]
where throttling was proposed and added to the server. In that thread,
it was originally implemented on the client-side, but per many
suggestions,
it was moved to server-side.

So, I have a few suggestions on how we can implement this:

1- have another option for pg_basebackup (i.e. per-worker-maxrate) where
the user could choose the bandwidth allocation for each worker. This
approach
can be implemented on the client-side as well as on the server-side.

2- have the maxrate, be divided among workers equally at first. and the
let the main thread keep adjusting it whenever one of the workers
finishes.
I believe this would only be possible if we handle throttling on the
client.
Also, as I understand it, implementing this will introduce additional
mutex
for handling of bandwidth consumption data so that rate may be adjusted
according to data received by threads.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

The latest changes look good to me. However, the patch set is missing the
documentation.
Please add those.

Thanks

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0006-parallel-backup-documentation.patchapplication/octet-stream; name=0006-parallel-backup-documentation.patchDownload
From 7fd87b7dcb9c626fa6abb3d526de284a93f232c5 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Fri, 14 Feb 2020 17:02:51 +0500
Subject: [PATCH 6/6] parallel backup - documentation

---
 doc/src/sgml/protocol.sgml          | 366 ++++++++++++++++++++++++++++
 doc/src/sgml/ref/pg_basebackup.sgml |  19 ++
 2 files changed, 385 insertions(+)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 80275215e0..e332d1ac45 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2700,6 +2700,372 @@ The commands accepted in replication mode are:
      </para>
     </listitem>
   </varlistentry>
+  
+  <varlistentry>
+    <term><literal>START_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>FAST</literal> ]
+     <indexterm><primary>START_BACKUP</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instructs the server to prepare for performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><literal>LABEL</literal> <replaceable>'label'</replaceable></term>
+        <listitem>
+         <para>
+          Sets the label of the backup. If none is specified, a backup label
+          of <literal>start backup</literal> will be used. The quoting rules
+          for the label are the same as a standard SQL string with
+          <xref linkend="guc-standard-conforming-strings"/> turned on.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>FAST</literal></term>
+        <listitem>
+         <para>
+          Request a fast checkpoint.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a single result set. The
+      first column contains the start position given in XLogRecPtr format, and
+      the second column contains the corresponding timeline ID.
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>STOP_BACKUP</literal>
+        [ <literal>NOWAIT</literal> ]
+     <indexterm><primary>STOP_BACKUP</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instructs the server to finish performing on-line backup.
+      <variablelist>
+       <varlistentry>
+        <term><literal>NOWAIT</literal></term>
+        <listitem>
+         <para>
+          By default, the backup will wait until the last required WAL
+          segment has been archived, or emit a warning if log archiving is
+          not enabled. Specifying <literal>NOWAIT</literal> disables both
+          the waiting and the warning, leaving the client responsible for
+          ensuring the required log is available.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a single result set. The
+      first column contains the start position given in XLogRecPtr format, the
+      second column contains the corresponding timeline ID and the third column
+      contains the contents of the <filename>backup_label</filename> file.
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>LIST_TABLESPACES</literal>
+        [ <literal>PROGRESS</literal> ]
+      <indexterm><primary>LIST_TABLESPACES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instruct the server to return a list of tablespaces available in data
+      directory.
+      <variablelist>
+       <varlistentry>
+        <term><literal>PROGRESS</literal></term>
+        <listitem>
+         <para>
+          Request information required to generate a progress report. This will
+          send back an approximate size in the header of each tablespace, which
+          can be used to calculate how far along the stream is done. This is
+          calculated by enumerating all the file sizes once before the transfer
+          is even started, and might as such have a negative impact on the
+          performance.  In particular, it might take longer before the first data
+          is streamed. Since the database files can change during the backup,
+          the size is only approximate and might both grow and shrink between
+          the time of approximation and the sending of the actual files.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send one result set.
+      The result set will have one row for each tablespace. The fields in this
+      row are:
+      <variablelist>
+       <varlistentry>
+        <term><literal>spcoid</literal> (<type>oid</type>)</term>
+        <listitem>
+         <para>
+          The OID of the tablespace, or null if it's the base directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>spclocation</literal> (<type>text</type>)</term>
+        <listitem>
+         <para>
+          The full path of the tablespace directory, or null if it's the base
+          directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+        <para>
+         The approximate size of the tablespace, in kilobytes (1024 bytes),
+         if progress report has been requested; otherwise it's null.
+        </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>LIST_FILES</literal>
+        [ <literal>TABLESPACE</literal> ]
+     <indexterm><primary>LIST_FILES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      This command instructs the server to return a list of files available
+      in the given tablespace.
+      <variablelist>
+       <varlistentry>
+        <term><literal>TABLESPACE</literal></term>
+        <listitem>
+         <para>
+          name of the tablespace. If its empty or not provided then 'base' tablespace
+          is assumed.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a result set. The fields
+      in this result set are:
+      <variablelist>
+       <varlistentry>
+        <term><literal>path</literal> (<type>text</type>)</term>
+        <listitem>
+         <para>
+          The path and name of the file. In case of tablespace, it is an absolute
+          path on the database server, however, in case of <filename>base</filename>
+          tablespace, it is relative to $PGDATA.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>type</literal> (<type>char</type>)</term>
+        <listitem>
+         <para>
+          A single character, identifying the type of file.
+          <itemizedlist spacing="compact" mark="bullet">
+           <listitem>
+            <para>
+             <literal>'f'</literal> - Regular file. Can be any relation or
+             non-relation file in $PGDATA.
+            </para>
+           </listitem>
+           <listitem>
+            <para>
+             <literal>'d'</literal> - Directory.
+            </para>
+           </listitem>
+           <listitem>
+            <para>
+             <literal>'l'</literal> - Symbolic link.
+            </para>
+           </listitem>
+          </itemizedlist>
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the file, in kilobytes (1024 bytes). It's null
+          if type is 'd' or 'l'.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>mtime</literal> (<type>Int64</type>)</term>
+        <listitem>
+         <para>
+          The file or directory last modification time, as seconds since the Epoch.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      The list will contain all files in tablespace directory, regardless of whether
+      they are PostgreSQL files or other files added to the same directory. The only
+      excluded files are:
+      <itemizedlist spacing="compact" mark="bullet">
+       <listitem>
+        <para>
+         <filename>postmaster.pid</filename>
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>postmaster.opts</filename>
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>pg_internal.init</filename> (found in multiple directories)
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         Various temporary files and directories created during the operation
+         of the PostgreSQL server, such as any file or directory beginning
+         with <filename>pgsql_tmp</filename> and temporary relations.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         Unlogged relations, except for the init fork which is required to
+         recreate the (empty) unlogged relation on recovery.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>pg_wal</filename>, including subdirectories. If the backup is run
+         with WAL files included, a synthesized version of <filename>pg_wal</filename>
+         will be included, but it will only contain the files necessary for the backup
+         to work, not the rest of the contents.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>pg_dynshmem</filename>, <filename>pg_notify</filename>,
+         <filename>pg_replslot</filename>, <filename>pg_serial</filename>,
+         <filename>pg_snapshots</filename>, <filename>pg_stat_tmp</filename>, and
+         <filename>pg_subtrans</filename> are copied as empty directories (even if
+         they are symbolic links).
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         Files other than regular files and directories, such as symbolic
+         links (other than for the directories listed above) and special
+         device files, are skipped.  (Symbolic links
+         in <filename>pg_tblspc</filename> are maintained.)
+        </para>
+       </listitem>
+      </itemizedlist>
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>LIST_WAL_FILES</literal>
+        <literal>START_WAL_LOCATION</literal> <replaceable class="parameter">X/X</replaceable>
+        <literal>END_WAL_LOCATION</literal> <replaceable class="parameter">X/X</replaceable>
+      <indexterm><primary>LIST_WAL_FILES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instruct the server to return a list of WAL files available in pg_wal directory.
+      The following options are accepted:
+      <variablelist>
+       <varlistentry>
+         <term><literal>START_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The starting WAL position when START BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><literal>END_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The ending WAL position when STOP BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a result and each row will
+      consist of a WAL file entry. The result set will have the same fields as
+      <literal>LIST_FILES</literal> command.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_FILES ( <replaceable class="parameter">'FILE'</replaceable> [, ...] )</literal>
+        [ <literal>START_WAL_LOCATION</literal> <replaceable class="parameter">X/X</replaceable> ]
+        [ <literal>NOVERIFY_CHECKSUMS</literal> ]
+        <indexterm><primary>SEND_FILES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instructs the server to send the contents of the requested FILE(s).
+     </para>
+     <para>
+      A clause of the form <literal>SEND_FILES ( 'FILE', 'FILE', ... ) [OPTIONS]</literal>
+      is accepted where one or more FILE(s) can be requested.
+     </para>
+     <para>
+      In response to this command, one or more CopyResponse results will be sent,
+      one for each FILE requested. The data in the CopyResponse results will be
+      a tar format (following the “ustar interchange format” specified in the
+      POSIX 1003.1-2008 standard) dump of the tablespace contents, except that
+      the two trailing blocks of zeroes specified in the standard are omitted.
+     </para>
+     <para>
+      The following options are accepted:
+      <variablelist>
+       <varlistentry>
+         <term><literal>START_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The starting WAL position when START BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><literal>NOVERIFY_CHECKSUMS</literal></term>
+         <listitem>
+          <para>
+           By default, checksums are verified during a base backup if they are
+           enabled. Specifying <literal>NOVERIFY_CHECKSUMS</literal> disables
+           this verification.
+          </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+    </listitem>
+  </varlistentry>
 </variablelist>
 
 </para>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index fc9e222f8d..3b1d9c9ba6 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -536,6 +536,25 @@ PostgreSQL documentation
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry>
+      <term><option>-j <replaceable class="parameter">n</replaceable></option></term>
+      <term><option>--jobs=<replaceable class="parameter">n</replaceable></option></term>
+      <listitem>
+       <para>
+        Create <replaceable class="parameter">n</replaceable> threads to copy
+        backup files from the database server. <application>pg_basebackup</application>
+        will open <replaceable class="parameter">n</replaceable> +1 connections
+        to the database. Therefore, the server must be configured with
+        <xref linkend="guc-max-wal-senders"/> set high enough to accommodate all
+        connections.
+       </para>
+       <para>
+        parallel mode only works with plain format.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </para>
 
-- 
2.21.1 (Apple Git-122.3)

#45Asif Rehman
asifr.rehman@gmail.com
In reply to: Asif Rehman (#44)
Re: WIP/PoC for parallel backup

Hi,

I have created a commitfest entry.
https://commitfest.postgresql.org/27/2472/

On Mon, Feb 17, 2020 at 1:39 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Thanks Jeevan. Here is the documentation patch.

On Mon, Feb 10, 2020 at 6:49 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

On Thu, Jan 30, 2020 at 7:10 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Here are the the updated patches, taking care of the issues pointed
earlier. This patch adds the following commands (with specified option):

START_BACKUP [LABEL '<label>'] [FAST]
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILES '(' FILE, FILE... ')' [START_WAL_LOCATION 'X/X']
[NOVERIFY_CHECKSUMS]

Parallel backup is not making any use of tablespace map, so I have
removed that option from the above commands. There is a patch pending
to remove the exclusive backup; we can further refactor the
do_pg_start_backup
function at that time, to remove the tablespace information and move the
creation of tablespace_map file to the client.

I have disabled the maxrate option for parallel backup. I intend to send
out a separate patch for it. Robert previously suggested to implement
throttling on the client-side. I found the original email thread [1]
where throttling was proposed and added to the server. In that thread,
it was originally implemented on the client-side, but per many
suggestions,
it was moved to server-side.

So, I have a few suggestions on how we can implement this:

1- have another option for pg_basebackup (i.e. per-worker-maxrate) where
the user could choose the bandwidth allocation for each worker. This
approach
can be implemented on the client-side as well as on the server-side.

2- have the maxrate, be divided among workers equally at first. and the
let the main thread keep adjusting it whenever one of the workers
finishes.
I believe this would only be possible if we handle throttling on the
client.
Also, as I understand it, implementing this will introduce additional
mutex
for handling of bandwidth consumption data so that rate may be adjusted
according to data received by threads.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

The latest changes look good to me. However, the patch set is missing the
documentation.
Please add those.

Thanks

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#46Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Asif Rehman (#45)
Re: WIP/PoC for parallel backup

Hi Asif

I have started testing this feature. I have applied v6 patch on commit
a069218163704c44a8996e7e98e765c56e2b9c8e (30 Jan).
I got few observations, please take a look.

*--if backup failed, backup directory is not getting removed.*
[edb@localhost bin]$ ./pg_basebackup -p 5432 --jobs=9 -D /tmp/test_bkp/bkp6
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
[edb@localhost bin]$ ./pg_basebackup -p 5432 --jobs=8 -D /tmp/test_bkp/bkp6
pg_basebackup: error: directory "/tmp/test_bkp/bkp6" exists but is not empty

*--giving large number of jobs leading segmentation fault.*
./pg_basebackup -p 5432 --jobs=1000 -D /tmp/t3
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
.
.
.
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: could not fork new
process for connection: Resource temporarily unavailable

could not fork new process for connection: Resource temporarily unavailable
pg_basebackup: error: failed to create thread: Resource temporarily
unavailable
Segmentation fault (core dumped)

--stack-trace
gdb -q -c core.11824 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 --jobs=1000 -D
/tmp/test_bkp/bkp10'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=140503120623360, thread_return=0x0) at
pthread_join.c:46
46 if (INVALID_NOT_TERMINATED_TD_P (pd))
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 pthread_join (threadid=140503120623360, thread_return=0x0) at
pthread_join.c:46
#1 0x0000000000408e21 in cleanup_workers () at pg_basebackup.c:2840
#2 0x0000000000403846 in disconnect_atexit () at pg_basebackup.c:316
#3 0x0000003921235a02 in __run_exit_handlers (status=1) at exit.c:78
#4 exit (status=1) at exit.c:100
#5 0x0000000000408aa6 in create_parallel_workers (backupinfo=0x1a4b8c0) at
pg_basebackup.c:2713
#6 0x0000000000407946 in BaseBackup () at pg_basebackup.c:2127
#7 0x000000000040895c in main (argc=6, argv=0x7ffd566f4718) at
pg_basebackup.c:2668

*--with tablespace is in the same directory as data, parallel_backup
crashed*
[edb@localhost bin]$ ./initdb -D /tmp/data
[edb@localhost bin]$ ./pg_ctl -D /tmp/data -l /tmp/logfile start
[edb@localhost bin]$ mkdir /tmp/ts
[edb@localhost bin]$ ./psql postgres
psql (13devel)
Type "help" for help.

postgres=# create tablespace ts location '/tmp/ts';
CREATE TABLESPACE
postgres=# create table tx (a int) tablespace ts;
CREATE TABLE
postgres=# \q
[edb@localhost bin]$ ./pg_basebackup -j 2 -D /tmp/tts -T /tmp/ts=/tmp/ts1
Segmentation fault (core dumped)

--stack-trace
[edb@localhost bin]$ gdb -q -c core.15778 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -j 2 -D /tmp/tts -T
/tmp/ts=/tmp/ts1'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000000000409442 in get_backup_filelist (conn=0x140cb20,
backupInfo=0x14210a0) at pg_basebackup.c:3000
3000 backupInfo->curr->next = file;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x0000000000409442 in get_backup_filelist (conn=0x140cb20,
backupInfo=0x14210a0) at pg_basebackup.c:3000
#1 0x0000000000408b56 in parallel_backup_run (backupinfo=0x14210a0) at
pg_basebackup.c:2739
#2 0x0000000000407955 in BaseBackup () at pg_basebackup.c:2128
#3 0x000000000040895c in main (argc=7, argv=0x7ffca2910c58) at
pg_basebackup.c:2668
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Tue, Feb 25, 2020 at 7:49 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Show quoted text

Hi,

I have created a commitfest entry.
https://commitfest.postgresql.org/27/2472/

On Mon, Feb 17, 2020 at 1:39 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Thanks Jeevan. Here is the documentation patch.

On Mon, Feb 10, 2020 at 6:49 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

On Thu, Jan 30, 2020 at 7:10 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Here are the the updated patches, taking care of the issues pointed
earlier. This patch adds the following commands (with specified option):

START_BACKUP [LABEL '<label>'] [FAST]
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILES '(' FILE, FILE... ')' [START_WAL_LOCATION 'X/X']
[NOVERIFY_CHECKSUMS]

Parallel backup is not making any use of tablespace map, so I have
removed that option from the above commands. There is a patch pending
to remove the exclusive backup; we can further refactor the
do_pg_start_backup
function at that time, to remove the tablespace information and move the
creation of tablespace_map file to the client.

I have disabled the maxrate option for parallel backup. I intend to send
out a separate patch for it. Robert previously suggested to implement
throttling on the client-side. I found the original email thread [1]
where throttling was proposed and added to the server. In that thread,
it was originally implemented on the client-side, but per many
suggestions,
it was moved to server-side.

So, I have a few suggestions on how we can implement this:

1- have another option for pg_basebackup (i.e. per-worker-maxrate) where
the user could choose the bandwidth allocation for each worker. This
approach
can be implemented on the client-side as well as on the server-side.

2- have the maxrate, be divided among workers equally at first. and the
let the main thread keep adjusting it whenever one of the workers
finishes.
I believe this would only be possible if we handle throttling on the
client.
Also, as I understand it, implementing this will introduce additional
mutex
for handling of bandwidth consumption data so that rate may be adjusted
according to data received by threads.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

The latest changes look good to me. However, the patch set is missing
the documentation.
Please add those.

Thanks

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#47Asif Rehman
asifr.rehman@gmail.com
In reply to: Rajkumar Raghuwanshi (#46)
6 attachment(s)
Re: WIP/PoC for parallel backup

On Wed, Mar 11, 2020 at 2:38 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif

I have started testing this feature. I have applied v6 patch on commit
a069218163704c44a8996e7e98e765c56e2b9c8e (30 Jan).
I got few observations, please take a look.

*--if backup failed, backup directory is not getting removed.*
[edb@localhost bin]$ ./pg_basebackup -p 5432 --jobs=9 -D
/tmp/test_bkp/bkp6
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
[edb@localhost bin]$ ./pg_basebackup -p 5432 --jobs=8 -D
/tmp/test_bkp/bkp6
pg_basebackup: error: directory "/tmp/test_bkp/bkp6" exists but is not
empty

*--giving large number of jobs leading segmentation fault.*
./pg_basebackup -p 5432 --jobs=1000 -D /tmp/t3
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
.
.
.
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: could not fork new
process for connection: Resource temporarily unavailable

could not fork new process for connection: Resource temporarily unavailable
pg_basebackup: error: failed to create thread: Resource temporarily
unavailable
Segmentation fault (core dumped)

--stack-trace
gdb -q -c core.11824 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 --jobs=1000 -D
/tmp/test_bkp/bkp10'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=140503120623360, thread_return=0x0) at
pthread_join.c:46
46 if (INVALID_NOT_TERMINATED_TD_P (pd))
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 pthread_join (threadid=140503120623360, thread_return=0x0) at
pthread_join.c:46
#1 0x0000000000408e21 in cleanup_workers () at pg_basebackup.c:2840
#2 0x0000000000403846 in disconnect_atexit () at pg_basebackup.c:316
#3 0x0000003921235a02 in __run_exit_handlers (status=1) at exit.c:78
#4 exit (status=1) at exit.c:100
#5 0x0000000000408aa6 in create_parallel_workers (backupinfo=0x1a4b8c0)
at pg_basebackup.c:2713
#6 0x0000000000407946 in BaseBackup () at pg_basebackup.c:2127
#7 0x000000000040895c in main (argc=6, argv=0x7ffd566f4718) at
pg_basebackup.c:2668

*--with tablespace is in the same directory as data, parallel_backup
crashed*
[edb@localhost bin]$ ./initdb -D /tmp/data
[edb@localhost bin]$ ./pg_ctl -D /tmp/data -l /tmp/logfile start
[edb@localhost bin]$ mkdir /tmp/ts
[edb@localhost bin]$ ./psql postgres
psql (13devel)
Type "help" for help.

postgres=# create tablespace ts location '/tmp/ts';
CREATE TABLESPACE
postgres=# create table tx (a int) tablespace ts;
CREATE TABLE
postgres=# \q
[edb@localhost bin]$ ./pg_basebackup -j 2 -D /tmp/tts -T /tmp/ts=/tmp/ts1
Segmentation fault (core dumped)

--stack-trace
[edb@localhost bin]$ gdb -q -c core.15778 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -j 2 -D /tmp/tts -T
/tmp/ts=/tmp/ts1'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000000000409442 in get_backup_filelist (conn=0x140cb20,
backupInfo=0x14210a0) at pg_basebackup.c:3000
3000 backupInfo->curr->next = file;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x0000000000409442 in get_backup_filelist (conn=0x140cb20,
backupInfo=0x14210a0) at pg_basebackup.c:3000
#1 0x0000000000408b56 in parallel_backup_run (backupinfo=0x14210a0) at
pg_basebackup.c:2739
#2 0x0000000000407955 in BaseBackup () at pg_basebackup.c:2128
#3 0x000000000040895c in main (argc=7, argv=0x7ffca2910c58) at
pg_basebackup.c:2668
(gdb)

Thanks Rajkumar. I have fixed the above issues and have rebased the patch
to the latest master (b7f64c64).
(V9 of the patches are attached).

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v9.patchapplication/octet-stream; name=0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb_v9.patchDownload
From b5b8694e2a61b084508ced9a49d462160d692b58 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Wed, 30 Oct 2019 16:45:28 +0500
Subject: [PATCH 1/6] Rename sizeonly to dryrun for few functions in
 basebackup.

---
 src/backend/replication/basebackup.c | 44 ++++++++++++++--------------
 src/include/replication/basebackup.h |  2 +-
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 806d013108d..ca074d59ac9 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -55,15 +55,15 @@ typedef struct
 } basebackup_options;
 
 
-static int64 sendDir(const char *path, int basepathlen, bool sizeonly,
+static int64 sendDir(const char *path, int basepathlen, bool dryrun,
 					 List *tablespaces, bool sendtblspclinks);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
 static int64 _tarWriteHeader(const char *filename, const char *linktarget,
-							 struct stat *statbuf, bool sizeonly);
+							 struct stat *statbuf, bool dryrun);
 static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-						  bool sizeonly);
+						  bool dryrun);
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void perform_base_backup(basebackup_options *opt);
@@ -1021,13 +1021,13 @@ sendFileWithContent(const char *filename, const char *content)
 
 /*
  * Include the tablespace directory pointed to by 'path' in the output tar
- * stream.  If 'sizeonly' is true, we just calculate a total length and return
+ * stream.  If 'dryrun' is true, we just calculate a total length and return
  * it, without actually sending anything.
  *
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool sizeonly)
+sendTablespace(char *path, bool dryrun)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -1057,17 +1057,17 @@ sendTablespace(char *path, bool sizeonly)
 	}
 
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
-						   sizeonly);
+						   dryrun);
 
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), sizeonly, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
 
 	return size;
 }
 
 /*
  * Include all files from the given directory in the output tar stream. If
- * 'sizeonly' is true, we just calculate a total length and return it, without
+ * 'dryrun' is true, we just calculate a total length and return it, without
  * actually sending anything.
  *
  * Omit any directory in the tablespaces list, to avoid backing up
@@ -1078,7 +1078,7 @@ sendTablespace(char *path, bool sizeonly)
  * as it will be sent separately in the tablespace_map file.
  */
 static int64
-sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
+sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		bool sendtblspclinks)
 {
 	DIR		   *dir;
@@ -1237,7 +1237,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
-				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
 			}
@@ -1253,7 +1253,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
 
@@ -1265,14 +1265,14 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 		if (strcmp(pathbuf, "./pg_wal") == 0)
 		{
 			/* If pg_wal is a symlink, write it as a directory anyway */
-			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, sizeonly);
+			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 
 			/*
 			 * Also send archive_status directory (by hackishly reusing
 			 * statbuf from above ...).
 			 */
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			continue;			/* don't recurse into pg_wal */
 		}
@@ -1304,7 +1304,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			linkpath[rllen] = '\0';
 
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
-									&statbuf, sizeonly);
+									&statbuf, dryrun);
 #else
 
 			/*
@@ -1328,7 +1328,7 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 			 * permissions right.
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
-									sizeonly);
+									dryrun);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1359,17 +1359,17 @@ sendDir(const char *path, int basepathlen, bool sizeonly, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, sizeonly, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!sizeonly)
+			if (!dryrun)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? atooid(lastDir + 1) : InvalidOid);
 
-			if (sent || sizeonly)
+			if (sent || dryrun)
 			{
 				/* Add size, rounded up to 512byte block */
 				size += ((statbuf.st_size + 511) & ~511);
@@ -1688,12 +1688,12 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
 
 static int64
 _tarWriteHeader(const char *filename, const char *linktarget,
-				struct stat *statbuf, bool sizeonly)
+				struct stat *statbuf, bool dryrun)
 {
 	char		h[512];
 	enum tarError rc;
 
-	if (!sizeonly)
+	if (!dryrun)
 	{
 		rc = tarCreateHeader(h, filename, linktarget, statbuf->st_size,
 							 statbuf->st_mode, statbuf->st_uid, statbuf->st_gid,
@@ -1731,7 +1731,7 @@ _tarWriteHeader(const char *filename, const char *linktarget,
  */
 static int64
 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
-			 bool sizeonly)
+			 bool dryrun)
 {
 	/* If symlink, write it as a directory anyway */
 #ifndef WIN32
@@ -1741,7 +1741,7 @@ _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
 #endif
 		statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
 
-	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
+	return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, dryrun);
 }
 
 /*
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index 07ed281bd63..e0210def6f3 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool sizeonly);
+extern int64 sendTablespace(char *path, bool dryrun);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.1 (Apple Git-122.3)

0004-Parallel-Backup-pg_basebackup_v9.patchapplication/octet-stream; name=0004-Parallel-Backup-pg_basebackup_v9.patchDownload
From 945cd4b33f3b98bddf849fcca3c2a091248f0142 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 27 Jan 2020 18:56:21 +0500
Subject: [PATCH 4/6] Parallel Backup - pg_basebackup

Implements the replication commands added in the backend replication
system and adds support for --jobs=NUM in pg_basebackup to take a full
backup in parallel using multiple connections. The utility will collect
a list of files from the server first and then workers will copy files
(one by one) over COPY protocol. The WAL files are also copied in similar
manner.
---
 src/bin/pg_basebackup/pg_basebackup.c | 1080 +++++++++++++++++++++++--
 1 file changed, 1015 insertions(+), 65 deletions(-)

diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 48bd838803b..7e392889809 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -13,6 +13,7 @@
 
 #include "postgres_fe.h"
 
+#include <pthread.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <sys/stat.h>
@@ -85,12 +86,65 @@ typedef struct UnpackTarState
 	const char *mapped_tblspc_path;
 	pgoff_t		current_len_left;
 	int			current_padding;
+	size_t		current_bytes_read;
 	FILE	   *file;
 } UnpackTarState;
 
 typedef void (*WriteDataCallback) (size_t nbytes, char *buf,
 								   void *callback_data);
 
+typedef struct BackupFile
+{
+	char		path[MAXPGPATH];
+	char		type;
+	int32		size;
+	time_t		mtime;
+
+	int			tsindex;		/* index of tsInfo this file belongs to. */
+	struct BackupFile *next;
+} BackupFile;
+
+typedef enum BackupState
+{
+	PB_FETCH_REL_LIST,
+	PB_FETCH_REL_FILES,
+	PB_FETCH_WAL_LIST,
+	PB_FETCH_WAL_FILES,
+	PB_STOP_BACKUP,
+	PB_BACKUP_COMPLETE
+} BackupState;
+
+typedef struct BackupInfo
+{
+	int			totalfiles;
+	uint64		bytes_skipped;
+	char		xlogstart[64];
+	char		xlogend[64];
+	BackupFile *files;			/* list of BackupFile pointers */
+	BackupFile *curr;			/* pointer to the file in the list */
+	BackupState backupstate;
+	bool		workersdone;
+	int			activeworkers;
+} BackupInfo;
+
+typedef struct WorkerState
+{
+	pthread_t	worker;
+	int			workerid;
+	BackupInfo *backupinfo;
+	PGconn	   *conn;
+	uint64		bytesread;
+} WorkerState;
+
+BackupInfo *backupinfo = NULL;
+WorkerState *workers = NULL;
+
+/* lock to be used for fetching file from the files list. */
+static pthread_mutex_t fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* condition to be used when the files list is filled. */
+static pthread_cond_t data_ready = PTHREAD_COND_INITIALIZER;
+
 /*
  * pg_xlog has been renamed to pg_wal in version 10.  This version number
  * should be compared with PQserverVersion().
@@ -144,6 +198,9 @@ static bool found_existing_xlogdir = false;
 static bool made_tablespace_dirs = false;
 static bool found_tablespace_dirs = false;
 
+static int	numWorkers = 1;
+static PGresult *tablespacehdr;
+
 /* Progress counters */
 static uint64 totalsize_kb;
 static uint64 totaldone;
@@ -174,10 +231,12 @@ static PQExpBuffer recoveryconfcontents = NULL;
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found);
 static void progress_report(int tablespacenum, const char *filename, bool force);
+static void workers_progress_report(uint64 totalBytesRead,
+									const char *filename, bool force);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveTarCopyChunk(size_t r, char *copybuf, void *callback_data);
-static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
+static int	ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf,
 										 void *callback_data);
 static void BaseBackup(void);
@@ -188,6 +247,22 @@ static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
 static const char *get_tablespace_mapping(const char *dir);
 static void tablespace_list_append(const char *arg);
 
+static void *worker_run(void *arg);
+static void create_parallel_workers(BackupInfo *backupInfo);
+static void parallel_backup_run(BackupInfo *backupInfo);
+static void cleanup_workers(void);
+static void stop_backup(void);
+static void get_backup_filelist(PGconn *conn, BackupInfo *backupInfo);
+static void get_wal_filelist(PGconn *conn, BackupInfo *backupInfo,
+							 char *xlogstart, char *xlogend);
+static void free_filelist(BackupInfo *backupInfo);
+static int	worker_get_files(WorkerState *wstate);
+static int	receive_file(PGconn *conn, char *file, int tsIndex);
+static void create_backup_dirs(bool basetablespace, char *tablespace,
+							   char *name);
+static void create_tblspc_symlink(char *filename);
+static void writefile(char *path, char *buf);
+static int	fetch_max_wal_senders(PGconn *conn);
 
 static void
 cleanup_directories_atexit(void)
@@ -239,6 +314,8 @@ cleanup_directories_atexit(void)
 static void
 disconnect_atexit(void)
 {
+	cleanup_workers();
+
 	if (conn != NULL)
 		PQfinish(conn);
 }
@@ -386,6 +463,7 @@ usage(void)
 	printf(_("      --no-slot          prevent creation of temporary replication slot\n"));
 	printf(_("      --no-verify-checksums\n"
 			 "                         do not verify checksums\n"));
+	printf(_("  -j, --jobs=NUM         use this many parallel jobs to backup\n"));
 	printf(_("  -?, --help             show this help, then exit\n"));
 	printf(_("\nConnection options:\n"));
 	printf(_("  -d, --dbname=CONNSTR   connection string\n"));
@@ -733,6 +811,94 @@ verify_dir_is_empty_or_create(char *dirname, bool *created, bool *found)
 	}
 }
 
+/*
+ * Print a progress report of worker threads. If verbose output
+ * is enabled, also print the current file name.
+ *
+ * Progress report is written at maximum once per second, unless the
+ * force parameter is set to true.
+ */
+static void
+workers_progress_report(uint64 totalBytesRead, const char *filename, bool force)
+{
+	int			percent;
+	char		totalBytesRead_str[32];
+	char		totalsize_str[32];
+	pg_time_t	now;
+
+	if (!showprogress)
+		return;
+
+	now = time(NULL);
+	if (now == last_progress_report && !force)
+		return;					/* Max once per second */
+
+	last_progress_report = now;
+	percent = totalsize_kb ? (int) ((totalBytesRead / 1024) * 100 / totalsize_kb) : 0;
+
+	/*
+	 * Avoid overflowing past 100% or the full size. This may make the total
+	 * size number change as we approach the end of the backup (the estimate
+	 * will always be wrong if WAL is included), but that's better than having
+	 * the done column be bigger than the total.
+	 */
+	if (percent > 100)
+		percent = 100;
+	if (totalBytesRead / 1024 > totalsize_kb)
+		totalsize_kb = totalBytesRead / 1024;
+
+	/*
+	 * Separate step to keep platform-dependent format code out of
+	 * translatable strings.  And we only test for INT64_FORMAT availability
+	 * in snprintf, not fprintf.
+	 */
+	snprintf(totalBytesRead_str, sizeof(totalBytesRead_str), INT64_FORMAT,
+			 totalBytesRead / 1024);
+	snprintf(totalsize_str, sizeof(totalsize_str), INT64_FORMAT, totalsize_kb);
+
+#define VERBOSE_FILENAME_LENGTH 35
+
+	if (verbose)
+	{
+		if (!filename)
+
+			/*
+			 * No filename given, so clear the status line (used for last
+			 * call)
+			 */
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied %*s"),
+					(int) strlen(totalsize_str),
+					totalBytesRead_str, totalsize_str,
+					percent,
+					VERBOSE_FILENAME_LENGTH + 5, "");
+		else
+		{
+			bool		truncate = (strlen(filename) > VERBOSE_FILENAME_LENGTH);
+
+			fprintf(stderr, _("%*s/%s kB (%d%%) copied, current file (%s%-*.*s)"),
+					(int) strlen(totalsize_str), totalBytesRead_str, totalsize_str,
+					percent,
+			/* Prefix with "..." if we do leading truncation */
+					truncate ? "..." : "",
+					truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+					truncate ? VERBOSE_FILENAME_LENGTH - 3 : VERBOSE_FILENAME_LENGTH,
+			/* Truncate filename at beginning if it's too long */
+					truncate ? filename + strlen(filename) - VERBOSE_FILENAME_LENGTH + 3 : filename);
+		}
+	}
+	else
+	{
+		fprintf(stderr, _("%*s/%s kB (%d%%) copied"),
+				(int) strlen(totalsize_str),
+				totalBytesRead_str, totalsize_str,
+				percent);
+	}
+
+	if (isatty(fileno(stderr)))
+		fprintf(stderr, "\r");
+	else
+		fprintf(stderr, "\n");
+}
 
 /*
  * Print a progress report based on the global variables. If verbose output
@@ -749,7 +915,7 @@ progress_report(int tablespacenum, const char *filename, bool force)
 	char		totalsize_str[32];
 	pg_time_t	now;
 
-	if (!showprogress)
+	if (!showprogress || numWorkers > 1)
 		return;
 
 	now = time(NULL);
@@ -1439,7 +1605,7 @@ get_tablespace_mapping(const char *dir)
  * specified directory. If it's for another tablespace, it will be restored
  * in the original or mapped directory.
  */
-static void
+static int
 ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 {
 	UnpackTarState state;
@@ -1470,13 +1636,12 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 		exit(1);
 	}
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
-
 	/*
 	 * No data is synced here, everything is done for all tablespaces at the
 	 * end.
 	 */
+
+	return state.current_bytes_read;
 }
 
 static void
@@ -1499,6 +1664,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			exit(1);
 		}
 		totaldone += 512;
+		state->current_bytes_read += 512;
 
 		state->current_len_left = read_tar_number(&copybuf[124], 12);
 
@@ -1630,6 +1796,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			fclose(state->file);
 			state->file = NULL;
 			totaldone += r;
+			state->current_bytes_read += r;
 			return;
 		}
 
@@ -1639,6 +1806,7 @@ ReceiveTarAndUnpackCopyChunk(size_t r, char *copybuf, void *callback_data)
 			exit(1);
 		}
 		totaldone += r;
+		state->current_bytes_read += r;
 		progress_report(state->tablespacenum, state->filename, false);
 
 		state->current_len_left -= r;
@@ -1706,6 +1874,24 @@ BaseBackup(void)
 		exit(1);
 	}
 
+	if (numWorkers > 1)
+	{
+		int		max_wal_senders = fetch_max_wal_senders(conn);
+
+		/*
+		 * In parallel backup mode, pg_basebackup opens numWorkers + 2
+		 * connections. One of the two additional connections is used by the
+		 * main application while the other one is used if WAL streaming is
+		 * enabled (-X Stream).
+		 */
+		if (numWorkers + 2 > max_wal_senders)
+		{
+			pg_log_error("number of requested workers exceeds max_wal_senders (currently %d)",
+						 max_wal_senders);
+			exit(1);
+		}
+	}
+
 	/*
 	 * Build contents of configuration file if requested
 	 */
@@ -1738,16 +1924,26 @@ BaseBackup(void)
 			fprintf(stderr, "\n");
 	}
 
-	basebkp =
-		psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
-				 escaped_label,
-				 showprogress ? "PROGRESS" : "",
-				 includewal == FETCH_WAL ? "WAL" : "",
-				 fastcheckpoint ? "FAST" : "",
-				 includewal == NO_WAL ? "" : "NOWAIT",
-				 maxrate_clause ? maxrate_clause : "",
-				 format == 't' ? "TABLESPACE_MAP" : "",
-				 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	if (numWorkers <= 1)
+	{
+		basebkp =
+			psprintf("BASE_BACKUP LABEL '%s' %s %s %s %s %s %s %s",
+					 escaped_label,
+					 showprogress ? "PROGRESS" : "",
+					 includewal == FETCH_WAL ? "WAL" : "",
+					 fastcheckpoint ? "FAST" : "",
+					 includewal == NO_WAL ? "" : "NOWAIT",
+					 maxrate_clause ? maxrate_clause : "",
+					 format == 't' ? "TABLESPACE_MAP" : "",
+					 verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	}
+	else
+	{
+		basebkp =
+			psprintf("START_BACKUP LABEL '%s' %s",
+					 escaped_label,
+					 fastcheckpoint ? "FAST" : "");
+	}
 
 	if (PQsendQuery(conn, basebkp) == 0)
 	{
@@ -1794,10 +1990,36 @@ BaseBackup(void)
 		pg_log_info("write-ahead log start point: %s on timeline %u",
 					xlogstart, starttli);
 
+	if (numWorkers > 1)
+	{
+		/*
+		 * Finish up the START_BACKUP command execution and make sure we have
+		 * CommandComplete.
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data for '%s': %s", "START_BACKUP",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		res = PQgetResult(conn);
+
+		basebkp = psprintf("LIST_TABLESPACES %s",
+						   showprogress ? "PROGRESS" : "");
+
+		if (PQsendQuery(conn, basebkp) == 0)
+		{
+			pg_log_error("could not send replication command \"%s\": %s",
+						 "LIST_TABLESPACES", PQerrorMessage(conn));
+			exit(1);
+		}
+	}
+
 	/*
 	 * Get the header
 	 */
-	res = PQgetResult(conn);
+	tablespacehdr = res = PQgetResult(conn);
 	if (PQresultStatus(res) != PGRES_TUPLES_OK)
 	{
 		pg_log_error("could not get backup header: %s",
@@ -1853,65 +2075,98 @@ BaseBackup(void)
 		StartLogStreamer(xlogstart, starttli, sysidentifier);
 	}
 
-	/*
-	 * Start receiving chunks
-	 */
-	for (i = 0; i < PQntuples(res); i++)
-	{
-		if (format == 't')
-			ReceiveTarFile(conn, res, i);
-		else
-			ReceiveAndUnpackTarFile(conn, res, i);
-	}							/* Loop over all tablespaces */
-
-	if (showprogress)
+	if (numWorkers <= 1)
 	{
-		progress_report(PQntuples(res), NULL, true);
-		if (isatty(fileno(stderr)))
-			fprintf(stderr, "\n");	/* Need to move to next line */
-	}
+		/*
+		 * Start receiving chunks
+		 */
+		for (i = 0; i < PQntuples(res); i++)
+		{
+			if (format == 't')
+				ReceiveTarFile(conn, res, i);
+			else
+				ReceiveAndUnpackTarFile(conn, res, i);
+		}						/* Loop over all tablespaces */
 
-	PQclear(res);
+		if (showprogress)
+		{
+			progress_report(PQntuples(tablespacehdr), NULL, true);
+			if (isatty(fileno(stderr)))
+				fprintf(stderr, "\n");	/* Need to move to next line */
+		}
 
-	/*
-	 * Get the stop position
-	 */
-	res = PQgetResult(conn);
-	if (PQresultStatus(res) != PGRES_TUPLES_OK)
-	{
-		pg_log_error("could not get write-ahead log end position from server: %s",
-					 PQerrorMessage(conn));
-		exit(1);
-	}
-	if (PQntuples(res) != 1)
-	{
-		pg_log_error("no write-ahead log end position returned from server");
-		exit(1);
-	}
-	strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
-	if (verbose && includewal != NO_WAL)
-		pg_log_info("write-ahead log end point: %s", xlogend);
-	PQclear(res);
+		PQclear(res);
 
-	res = PQgetResult(conn);
-	if (PQresultStatus(res) != PGRES_COMMAND_OK)
-	{
-		const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+		/*
+		 * Get the stop position
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not get write-ahead log end position from server: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) != 1)
+		{
+			pg_log_error("no write-ahead log end position returned from server");
+			exit(1);
+		}
+		strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
+		if (verbose && includewal != NO_WAL)
+			pg_log_info("write-ahead log end point: %s", xlogend);
+		PQclear(res);
 
-		if (sqlstate &&
-			strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
 		{
-			pg_log_error("checksum error occurred");
-			checksum_failure = true;
+			const char *sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+
+			if (sqlstate &&
+				strcmp(sqlstate, ERRCODE_DATA_CORRUPTED) == 0)
+			{
+				pg_log_error("checksum error occurred");
+				checksum_failure = true;
+			}
+			else
+			{
+				pg_log_error("final receive failed: %s",
+							 PQerrorMessage(conn));
+			}
+			exit(1);
 		}
-		else
+	}
+
+	if (numWorkers > 1)
+	{
+		/*
+		 * Finish up the LIST_TABLESPACES command execution and make sure we
+		 * have CommandComplete.
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
 		{
-			pg_log_error("final receive failed: %s",
+			pg_log_error("could not get data for '%s': %s", "LIST_TABLESPACES",
 						 PQerrorMessage(conn));
+			exit(1);
 		}
-		exit(1);
+		res = PQgetResult(conn);
+
+		backupinfo = palloc0(sizeof(BackupInfo));
+		backupinfo->backupstate = PB_FETCH_REL_LIST;
+
+		/* copy starting WAL location */
+		strlcpy(backupinfo->xlogstart, xlogstart, sizeof(backupinfo->xlogstart));
+		create_parallel_workers(backupinfo);
+		parallel_backup_run(backupinfo);
+		/* copy ending WAL location */
+		strlcpy(xlogend, backupinfo->xlogend, sizeof(xlogend));
 	}
 
+	/* Write recovery contents */
+	if (format == 'p' && writerecoveryconf)
+		WriteRecoveryConfig(conn, basedir, recoveryconfcontents);
+
 	if (bgchild > 0)
 	{
 #ifndef WIN32
@@ -2066,6 +2321,7 @@ main(int argc, char **argv)
 		{"waldir", required_argument, NULL, 1},
 		{"no-slot", no_argument, NULL, 2},
 		{"no-verify-checksums", no_argument, NULL, 3},
+		{"jobs", required_argument, NULL, 'j'},
 		{NULL, 0, NULL, 0}
 	};
 	int			c;
@@ -2093,7 +2349,7 @@ main(int argc, char **argv)
 
 	atexit(cleanup_directories_atexit);
 
-	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvP",
+	while ((c = getopt_long(argc, argv, "CD:F:r:RS:T:X:l:nNzZ:d:c:h:p:U:s:wWkvPj:",
 							long_options, &option_index)) != -1)
 	{
 		switch (c)
@@ -2234,6 +2490,9 @@ main(int argc, char **argv)
 			case 3:
 				verify_checksums = false;
 				break;
+			case 'j':			/* number of jobs */
+				numWorkers = atoi(optarg);
+				break;
 			default:
 
 				/*
@@ -2348,6 +2607,30 @@ main(int argc, char **argv)
 		}
 	}
 
+	if (numWorkers <= 0)
+	{
+		pg_log_error("invalid number of parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (format != 'p' && numWorkers > 1)
+	{
+		pg_log_error("parallel jobs are only supported with 'plain' format");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
+	if (maxrate > 0 && numWorkers > 1)
+	{
+		pg_log_error("--max-rate is not supported with parallel jobs");
+		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
+				progname);
+		exit(1);
+	}
+
 #ifndef HAVE_LIBZ
 	if (compresslevel != 0)
 	{
@@ -2420,3 +2703,670 @@ main(int argc, char **argv)
 	success = true;
 	return 0;
 }
+
+/*
+ * Worker thread function. Added for code readability.
+ */
+static void *
+worker_run(void *arg)
+{
+	WorkerState *wstate = (WorkerState *) arg;
+
+	worker_get_files(wstate);
+
+	return NULL;
+}
+
+/*
+ * Create workers and initialize worker state.
+ */
+static void
+create_parallel_workers(BackupInfo *backupinfo)
+{
+	int			status,
+				i;
+
+	workers = (WorkerState *) palloc(sizeof(WorkerState) * numWorkers);
+	backupinfo->activeworkers = 0;
+
+	for (i = 0; i < numWorkers; i++)
+	{
+		WorkerState *worker = &workers[i];
+
+		worker->backupinfo = backupinfo;
+		worker->bytesread = 0;
+		worker->workerid = i;
+		worker->conn = GetConnection();
+		backupinfo->activeworkers++;
+
+		status = pthread_create(&worker->worker, NULL, worker_run, worker);
+		if (status != 0)
+		{
+			pg_log_error("failed to create thread: %m");
+			exit(1);
+		}
+
+		if (verbose)
+			pg_log_info("backup worker (%d) created, %d", i, status);
+	}
+}
+
+/*
+ * This is the main function that controls the worker, assign tasks and does
+ * cleanup.
+ */
+static void
+parallel_backup_run(BackupInfo *backupinfo)
+{
+	uint64_t	totalread = 0;
+
+	while (1)
+	{
+		char	   *filename = NULL;
+
+		switch (backupinfo->backupstate)
+		{
+			case PB_FETCH_REL_LIST: /* get the list of files to fetch */
+				backupinfo->backupstate = PB_FETCH_REL_FILES;
+				/* retrieve backup file list from the server. */
+				get_backup_filelist(conn, backupinfo);
+				/* unblock any workers waiting on the condition */
+				pthread_cond_broadcast(&data_ready);
+				break;
+			case PB_FETCH_REL_FILES:	/* fetch files from server */
+				if (backupinfo->activeworkers == 0)
+				{
+					backupinfo->backupstate = PB_STOP_BACKUP;
+					free_filelist(backupinfo);
+				}
+				break;
+			case PB_FETCH_WAL_LIST: /* get the list of WAL files to fetch */
+				backupinfo->backupstate = PB_FETCH_WAL_FILES;
+				get_wal_filelist(conn, backupinfo, backupinfo->xlogstart, backupinfo->xlogend);
+				/* unblock any workers waiting on the condition */
+				pthread_cond_broadcast(&data_ready);
+				break;
+			case PB_FETCH_WAL_FILES:	/* fetch WAL files from server */
+				if (backupinfo->activeworkers == 0)
+				{
+					backupinfo->backupstate = PB_BACKUP_COMPLETE;
+				}
+				break;
+			case PB_STOP_BACKUP:
+
+				/*
+				 * All relation files have been fetched, time to stop the
+				 * backup, making sure to fetch the WAL files first (if needs
+				 * be).
+				 */
+				if (includewal == FETCH_WAL)
+					backupinfo->backupstate = PB_FETCH_WAL_LIST;
+				else
+					backupinfo->backupstate = PB_BACKUP_COMPLETE;
+
+				/* get the pg_control file at last. */
+				receive_file(conn, "global/pg_control", tablespacecount - 1);
+				stop_backup();
+				break;
+			case PB_BACKUP_COMPLETE:
+
+				/*
+				 * All relation and WAL files, (if needed) have been fetched,
+				 * now we can safly stop all workers and finish up.
+				 */
+				cleanup_workers();
+				if (showprogress)
+				{
+					workers_progress_report(totalread, NULL, true);
+					if (isatty(fileno(stderr)))
+						fprintf(stderr, "\n");	/* Need to move to next line */
+				}
+
+				/* nothing more to do here */
+				return;
+				break;
+			default:
+				/* shouldn't come here. */
+				pg_log_error("unexpected backup state: %d",
+							 backupinfo->backupstate);
+				exit(1);
+				break;
+		}
+
+		/* update and report progress */
+		totalread = 0;
+		for (int i = 0; i < numWorkers; i++)
+		{
+			WorkerState *worker = &workers[i];
+
+			totalread += worker->bytesread;
+		}
+		totalread += backupinfo->bytes_skipped;
+
+		if (backupinfo->curr != NULL)
+			filename = backupinfo->curr->path;
+
+		workers_progress_report(totalread, filename, false);
+		pg_usleep(100000);
+	}
+}
+
+/*
+ * Wait for the workers to complete the work and free connections.
+ */
+static void
+cleanup_workers(void)
+{
+	/* either non parallel backup */
+	if (!backupinfo)
+		return;
+	/* workers have already been stopped and cleanup has been done. */
+	if (backupinfo->workersdone)
+		return;
+
+	backupinfo->workersdone = true;
+	/* wakeup any workers waiting on the condition */
+	pthread_cond_broadcast(&data_ready);
+
+	for (int i = 0; i < numWorkers; i++)
+	{
+		pthread_join(workers[i].worker, NULL);
+		PQfinish(workers[i].conn);
+	}
+	free_filelist(backupinfo);
+}
+
+/*
+ * Take the system out of backup mode, also adds the backup_label file in
+ * the backup.
+ */
+static void
+stop_backup(void)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	basebkp = psprintf("STOP_BACKUP %s",
+					   includewal == NO_WAL ? "" : "NOWAIT");
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not execute STOP BACKUP \"%s\"",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	/*
+	 * Get the stop position
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not get write-ahead log end position from server: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	if (PQntuples(res) != 1)
+	{
+		pg_log_error("no write-ahead log end position returned from server");
+		exit(1);
+	}
+
+	/* retrieve the end wal location. */
+	strlcpy(backupinfo->xlogend, PQgetvalue(res, 0, 0),
+			sizeof(backupinfo->xlogend));
+
+	/* retrieve the backup_label file contents and write them to the backup */
+	writefile("backup_label", PQgetvalue(res, 0, 2));
+
+	PQclear(res);
+
+	/*
+	 * Finish up the Stop command execution and make sure we have
+	 * CommandComplete and ReadyForQuery response.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data %s", PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+
+	if (verbose && includewal != NO_WAL)
+		pg_log_info("write-ahead log end point: %s", backupinfo->xlogend);
+}
+
+/*
+ * Retrieves the list of files available in $PGDATA from the server.
+ */
+static void
+get_backup_filelist(PGconn *conn, BackupInfo *backupInfo)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+
+	for (int i = 0; i < tablespacecount; i++)
+	{
+		bool		basetablespace;
+		char	   *tablespace;
+		int			numFiles;
+
+		/*
+		 * Query server to fetch the file list for given tablespace name. If
+		 * the tablespace name is empty, it will fetch files list of 'base'
+		 * tablespace.
+		 */
+		basetablespace = PQgetisnull(tablespacehdr, i, 0);
+		tablespace = PQgetvalue(tablespacehdr, i, 1);
+
+		basebkp = psprintf("LIST_FILES '%s'",
+						   basetablespace ? "" : tablespace);
+		if (PQsendQuery(conn, basebkp) == 0)
+		{
+			pg_log_error("could not send replication command \"%s\": %s",
+						 "LIST_FILES", PQerrorMessage(conn));
+			exit(1);
+		}
+
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_TUPLES_OK)
+		{
+			pg_log_error("could not list backup files: %s",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		if (PQntuples(res) < 1)
+		{
+			pg_log_error("no data returned from server");
+			exit(1);
+		}
+
+		numFiles = PQntuples(res);
+		for (int j = 0; j < numFiles; j++)
+		{
+			BackupFile *file;
+			char	   *path = PQgetvalue(res, j, 0);
+			char		type = PQgetvalue(res, j, 1)[0];
+			int32		size = atol(PQgetvalue(res, j, 2));
+			time_t		mtime = atol(PQgetvalue(res, j, 3));
+
+			/*
+			 * In 'plain' format, create backup directories first.
+			 */
+			if (format == 'p' && type == 'd')
+			{
+				/*
+				 * directory entries are skipped. however, a tar header size
+				 * was included for them in totalsize_kb, so we need to add it
+				 * for progress reporting purpose.
+				 */
+				backupInfo->bytes_skipped += 512;
+				create_backup_dirs(basetablespace, tablespace, path);
+				continue;
+			}
+
+			if (format == 'p' && type == 'l')
+			{
+				/*
+				 * symlink entries are skipped. however, a tar header size was
+				 * included for them in totalsize_kb, so we need to add it for
+				 * progress reporting purpose.
+				 */
+				backupInfo->bytes_skipped += 512;
+				create_tblspc_symlink(path);
+				continue;
+			}
+
+			file = (BackupFile *) palloc(sizeof(BackupFile));
+			strlcpy(file->path, path, MAXPGPATH);
+			file->type = type;
+			file->size = size;
+			file->mtime = mtime;
+			file->tsindex = i;
+
+			/* add to the files list */
+			backupInfo->totalfiles++;
+			if (backupInfo->curr == NULL)
+				backupInfo->curr = backupInfo->files = file;
+			else
+			{
+				backupInfo->curr->next = file;
+				backupInfo->curr = backupInfo->curr->next;
+			}
+		}
+
+		PQclear(res);
+
+		/*
+		 * Finish up the LIST_FILES command execution and make sure we have
+		 * CommandComplete.
+		 */
+		res = PQgetResult(conn);
+		if (PQresultStatus(res) != PGRES_COMMAND_OK)
+		{
+			pg_log_error("could not get data for '%s': %s", "LIST_FILES",
+						 PQerrorMessage(conn));
+			exit(1);
+		}
+		res = PQgetResult(conn);
+	}
+
+	/* point curr to the head of list. */
+	backupInfo->curr = backupInfo->files;
+}
+
+/*
+ * Retrieve WAL file list from the server based on the starting wal location
+ * and ending wal location.
+ */
+static void
+get_wal_filelist(PGconn *conn, BackupInfo *backupInfo, char *xlogstart, char *xlogend)
+{
+	PGresult   *res = NULL;
+	char	   *basebkp;
+	int			numWals;
+
+	basebkp = psprintf("LIST_WAL_FILES START_WAL_LOCATION '%s' END_WAL_LOCATION '%s'",
+					   xlogstart, xlogend);
+
+	if (PQsendQuery(conn, basebkp) == 0)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "LIST_FILES", PQerrorMessage(conn));
+		exit(1);
+	}
+
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not list wal files: %s",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+
+	numWals = PQntuples(res);
+	for (int i = 0; i < numWals; i++)
+	{
+		BackupFile *file = (BackupFile *) palloc0(sizeof(BackupFile));
+
+		if (backupInfo->curr == NULL)
+			backupInfo->curr = backupInfo->files = file;
+		else
+		{
+			backupInfo->curr->next = file;
+			backupInfo->curr = file;
+		}
+
+		strlcpy(file->path, PQgetvalue(res, i, 0), MAXPGPATH);
+		file->tsindex = tablespacecount - 1;
+		backupInfo->totalfiles++;
+	}
+
+	/*
+	 * Finish up the LIST_WAL_FILES command execution and make sure we have
+	 * CommandComplete.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data for '%s': %s", "LIST_WAL_FILES",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+
+	/* point curr to the head of list. */
+	backupInfo->curr = backupInfo->files;
+}
+
+/* free files list */
+static void
+free_filelist(BackupInfo *backupInfo)
+{
+	/* free files list */
+	if (backupInfo->files != NULL)
+	{
+		backupInfo->curr = backupInfo->files;
+		while (backupInfo->curr != NULL)
+		{
+			BackupFile *file = backupInfo->curr;
+
+			backupInfo->curr = file->next;
+
+			pfree(file);
+		}
+
+		backupInfo->files = NULL;
+		backupInfo->totalfiles = 0;
+	}
+}
+
+/*
+ * Worker function to process and retrieve the files from the server. If the
+ * files list is empty, it will wait for it to be filled. Otherwise picks the
+ * next file in the list.
+ */
+static int
+worker_get_files(WorkerState *wstate)
+{
+	BackupFile *fetchfile = NULL;
+	BackupInfo *backupinfo = wstate->backupinfo;
+
+	while (!backupinfo->workersdone)
+	{
+		pthread_mutex_lock(&fetch_mutex);
+		if (backupinfo->curr == NULL)
+		{
+			/*
+			 * Wait until there is data available in the list to process.
+			 * pthread_cond_wait call unlocks the already locked mutex during
+			 * the wait state. When the condition is true (a signal is
+			 * raised), one of the competing threads acquires the mutex.
+			 */
+			backupinfo->activeworkers--;
+			pthread_cond_wait(&data_ready, &fetch_mutex);
+			backupinfo->activeworkers++;
+		}
+
+		fetchfile = backupinfo->curr;
+		if (fetchfile != NULL)
+		{
+			backupinfo->totalfiles--;
+			backupinfo->curr = fetchfile->next;
+		}
+		pthread_mutex_unlock(&fetch_mutex);
+
+		if (fetchfile != NULL)
+		{
+			wstate->bytesread +=
+				receive_file(wstate->conn, fetchfile->path, fetchfile->tsindex);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This function fetches the requested file from the server.
+ */
+static int
+receive_file(PGconn *conn, char *file, int tsIndex)
+{
+	PGresult   *res = NULL;
+	int			bytesread;
+	PQExpBuffer buf = createPQExpBuffer();
+
+	/*
+	 * Fetch a single file from the server. To fetch the file, build a query
+	 * in form of:
+	 *
+	 * SEND_FILES ('base/1/1245/32683') [options]
+	 */
+	appendPQExpBuffer(buf, "SEND_FILES ( '%s' )", file);
+
+	/* add options */
+	appendPQExpBuffer(buf, " START_WAL_LOCATION '%s' %s",
+					  backupinfo->xlogstart,
+					  verify_checksums ? "" : "NOVERIFY_CHECKSUMS");
+	if (!conn)
+		return 1;
+
+	if (PQsendQuery(conn, buf->data) == 0)
+	{
+		pg_log_error("could not send files list \"%s\"",
+					 PQerrorMessage(conn));
+		return 1;
+	}
+
+	destroyPQExpBuffer(buf);
+
+	/* process file contents, also count bytesRead for progress */
+	bytesread = ReceiveAndUnpackTarFile(conn, tablespacehdr, tsIndex);
+
+	PQclear(res);
+
+	/*
+	 * Finish up the SEND_FILES command execution and make sure we have
+	 * CommandComplete.
+	 */
+	res = PQgetResult(conn);
+	if (PQresultStatus(res) != PGRES_COMMAND_OK)
+	{
+		pg_log_error("could not get data for '%s': %s", "SEND_FILES",
+					 PQerrorMessage(conn));
+		exit(1);
+	}
+	res = PQgetResult(conn);
+	return bytesread;
+}
+
+/*
+ * Create backup directories while taking care of tablespace path. If tablespace
+ * mapping (with -T) is given then the directory will be created on the mapped
+ * path.
+ */
+static void
+create_backup_dirs(bool basetablespace, char *tablespace, char *name)
+{
+	char		dirpath[MAXPGPATH];
+
+	Assert(name != NULL);
+
+	if (basetablespace)
+		snprintf(dirpath, sizeof(dirpath), "%s/%s", basedir, name);
+	else
+	{
+		Assert(tablespace != NULL);
+		snprintf(dirpath, sizeof(dirpath), "%s/%s",
+				 get_tablespace_mapping(tablespace), (name + strlen(tablespace) + 1));
+	}
+
+	if (pg_mkdir_p(dirpath, pg_dir_create_mode) != 0)
+	{
+		if (errno != EEXIST)
+		{
+			pg_log_error("could not create directory \"%s\": %m",
+						 dirpath);
+			exit(1);
+		}
+	}
+}
+
+/*
+ * Create a symlink in pg_tblspc and apply any tablespace mapping given on
+ * the command line (--tablespace-mapping).
+ */
+static void
+create_tblspc_symlink(char *filename)
+{
+	int			i;
+
+	for (i = 0; i < tablespacecount; i++)
+	{
+		char	   *tsoid = PQgetvalue(tablespacehdr, i, 0);
+
+		if (strstr(filename, tsoid) != NULL)
+		{
+			char	   *linkloc = psprintf("%s/%s", basedir, filename);
+			const char *mapped_tblspc_path = get_tablespace_mapping(PQgetvalue(tablespacehdr, i, 1));
+
+#ifdef HAVE_SYMLINK
+			if (symlink(mapped_tblspc_path, linkloc) != 0)
+			{
+				pg_log_error("could not create symbolic link from \"%s\" to \"%s\": %m",
+							 linkloc, mapped_tblspc_path);
+				exit(1);
+			}
+#else
+			pg_log_error("symlinks are not supported on this platform");
+			exit(1);
+#endif
+			free(linkloc);
+			break;
+		}
+	}
+}
+
+/*
+ * General function for writing to a file; creates one if it doesn't exist
+ */
+static void
+writefile(char *path, char *buf)
+{
+	FILE	   *f;
+	char		pathbuf[MAXPGPATH];
+
+	snprintf(pathbuf, MAXPGPATH, "%s/%s", basedir, path);
+	f = fopen(pathbuf, "w");
+	if (f == NULL)
+	{
+		pg_log_error("could not open file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fwrite(buf, strlen(buf), 1, f) != 1)
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+
+	if (fclose(f))
+	{
+		pg_log_error("could not write to file \"%s\": %m", pathbuf);
+		exit(1);
+	}
+}
+
+static int
+fetch_max_wal_senders(PGconn *conn)
+{
+	PGresult   *res;
+	int			max_wal_senders;
+
+	/* check connection existence */
+	Assert(conn != NULL);
+
+	res = PQexec(conn, "SHOW max_wal_senders");
+	if (PQresultStatus(res) != PGRES_TUPLES_OK)
+	{
+		pg_log_error("could not send replication command \"%s\": %s",
+					 "SHOW max_wal_senders", PQerrorMessage(conn));
+
+		PQclear(res);
+		return -1;
+	}
+
+	if (PQntuples(res) != 1 || PQnfields(res) < 1)
+	{
+		pg_log_error("could not fetch max wal senders: got %d rows and %d fields, expected %d rows and %d or more fields",
+					 PQntuples(res), PQnfields(res), 1, 1);
+
+		PQclear(res);
+		return false;
+	}
+
+	max_wal_senders = atoi(PQgetvalue(res, 0, 0));
+	PQclear(res);
+
+	return max_wal_senders;
+}
-- 
2.21.1 (Apple Git-122.3)

0002-Refactor-some-backup-code-to-increase-reusability.-T_v9.patchapplication/octet-stream; name=0002-Refactor-some-backup-code-to-increase-reusability.-T_v9.patchDownload
From 1d41fa411fc02db73a49277779baeb022f3ae82d Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 27 Jan 2020 17:48:10 +0500
Subject: [PATCH 2/6] Refactor some backup code to increase reusability. This
 commit adds two functions; collect_tablespaces and collect_wal_files. The
 code related to collect tablespace information is moved from
 do_pg_start_backup to collect_tablespaces function. Also, the code to collect
 wal files is moved from perform_base_backup to collect_wal_files.

This does not introduce any functional changes.
---
 src/backend/access/transam/xlog.c    | 191 ++++++++++++-----------
 src/backend/replication/basebackup.c | 217 +++++++++++++++------------
 src/include/access/xlog.h            |   2 +
 3 files changed, 219 insertions(+), 191 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 4fa446ffa42..f5670141126 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -10348,10 +10348,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 	PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
 	{
 		bool		gotUniqueStartpoint = false;
-		DIR		   *tblspcdir;
-		struct dirent *de;
-		tablespaceinfo *ti;
-		int			datadirpathlen;
 
 		/*
 		 * Force an XLOG file switch before the checkpoint, to ensure that the
@@ -10477,8 +10473,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 		if (exclusive)
 			tblspcmapfile = makeStringInfo();
 
-		datadirpathlen = strlen(DataDir);
-
 		/*
 		 * Report that we are now estimating the total backup size
 		 * if we're streaming base backup as requested by pg_basebackup
@@ -10487,91 +10481,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
 			pgstat_progress_update_param(PROGRESS_BASEBACKUP_PHASE,
 										 PROGRESS_BASEBACKUP_PHASE_ESTIMATE_BACKUP_SIZE);
 
-		/* Collect information about all tablespaces */
-		tblspcdir = AllocateDir("pg_tblspc");
-		while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
-		{
-			char		fullpath[MAXPGPATH + 10];
-			char		linkpath[MAXPGPATH];
-			char	   *relpath = NULL;
-			int			rllen;
-			StringInfoData buflinkpath;
-			char	   *s = linkpath;
-
-			/* Skip special stuff */
-			if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
-				continue;
-
-			snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
-
-#if defined(HAVE_READLINK) || defined(WIN32)
-			rllen = readlink(fullpath, linkpath, sizeof(linkpath));
-			if (rllen < 0)
-			{
-				ereport(WARNING,
-						(errmsg("could not read symbolic link \"%s\": %m",
-								fullpath)));
-				continue;
-			}
-			else if (rllen >= sizeof(linkpath))
-			{
-				ereport(WARNING,
-						(errmsg("symbolic link \"%s\" target is too long",
-								fullpath)));
-				continue;
-			}
-			linkpath[rllen] = '\0';
-
-			/*
-			 * Add the escape character '\\' before newline in a string to
-			 * ensure that we can distinguish between the newline in the
-			 * tablespace path and end of line while reading tablespace_map
-			 * file during archive recovery.
-			 */
-			initStringInfo(&buflinkpath);
-
-			while (*s)
-			{
-				if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
-					appendStringInfoChar(&buflinkpath, '\\');
-				appendStringInfoChar(&buflinkpath, *s++);
-			}
-
-			/*
-			 * Relpath holds the relative path of the tablespace directory
-			 * when it's located within PGDATA, or NULL if it's located
-			 * elsewhere.
-			 */
-			if (rllen > datadirpathlen &&
-				strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
-				IS_DIR_SEP(linkpath[datadirpathlen]))
-				relpath = linkpath + datadirpathlen + 1;
-
-			ti = palloc(sizeof(tablespaceinfo));
-			ti->oid = pstrdup(de->d_name);
-			ti->path = pstrdup(buflinkpath.data);
-			ti->rpath = relpath ? pstrdup(relpath) : NULL;
-			ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
-
-			if (tablespaces)
-				*tablespaces = lappend(*tablespaces, ti);
-
-			appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
-
-			pfree(buflinkpath.data);
-#else
-
-			/*
-			 * If the platform does not have symbolic links, it should not be
-			 * possible to have tablespaces - clearly somebody else created
-			 * them. Warn about it and ignore.
-			 */
-			ereport(WARNING,
-					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-					 errmsg("tablespaces are not supported on this platform")));
-#endif
-		}
-		FreeDir(tblspcdir);
+		collect_tablespaces(tablespaces, tblspcmapfile, infotbssize, needtblspcmapfile);
 
 		/*
 		 * Construct backup label file
@@ -12390,3 +12300,102 @@ XLogRequestWalReceiverReply(void)
 {
 	doRequestWalReceiverReply = true;
 }
+
+/*
+ * Collect information about all tablespaces.
+ */
+void
+collect_tablespaces(List **tablespaces, StringInfo tblspcmapfile,
+					bool infotbssize, bool needtblspcmapfile)
+{
+	DIR		   *tblspcdir;
+	struct dirent *de;
+	tablespaceinfo *ti;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	tblspcdir = AllocateDir("pg_tblspc");
+	while ((de = ReadDir(tblspcdir, "pg_tblspc")) != NULL)
+	{
+		char		fullpath[MAXPGPATH + 10];
+		char		linkpath[MAXPGPATH];
+		char	   *relpath = NULL;
+		int			rllen;
+		StringInfoData buflinkpath;
+		char	   *s = linkpath;
+
+		/* Skip special stuff */
+		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
+			continue;
+
+		snprintf(fullpath, sizeof(fullpath), "pg_tblspc/%s", de->d_name);
+
+#if defined(HAVE_READLINK) || defined(WIN32)
+		rllen = readlink(fullpath, linkpath, sizeof(linkpath));
+		if (rllen < 0)
+		{
+			ereport(WARNING,
+					(errmsg("could not read symbolic link \"%s\": %m",
+							fullpath)));
+			continue;
+		}
+		else if (rllen >= sizeof(linkpath))
+		{
+			ereport(WARNING,
+					(errmsg("symbolic link \"%s\" target is too long",
+							fullpath)));
+			continue;
+		}
+		linkpath[rllen] = '\0';
+
+		/*
+		 * Add the escape character '\\' before newline in a string to ensure
+		 * that we can distinguish between the newline in the tablespace path
+		 * and end of line while reading tablespace_map file during archive
+		 * recovery.
+		 */
+		initStringInfo(&buflinkpath);
+
+		while (*s)
+		{
+			if ((*s == '\n' || *s == '\r') && needtblspcmapfile)
+				appendStringInfoChar(&buflinkpath, '\\');
+			appendStringInfoChar(&buflinkpath, *s++);
+		}
+
+		/*
+		 * Relpath holds the relative path of the tablespace directory when
+		 * it's located within PGDATA, or NULL if it's located elsewhere.
+		 */
+		if (rllen > datadirpathlen &&
+			strncmp(linkpath, DataDir, datadirpathlen) == 0 &&
+			IS_DIR_SEP(linkpath[datadirpathlen]))
+			relpath = linkpath + datadirpathlen + 1;
+
+		ti = palloc(sizeof(tablespaceinfo));
+		ti->oid = pstrdup(de->d_name);
+		ti->path = pstrdup(buflinkpath.data);
+		ti->rpath = relpath ? pstrdup(relpath) : NULL;
+		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+
+		if (tablespaces)
+			*tablespaces = lappend(*tablespaces, ti);
+
+		appendStringInfo(tblspcmapfile, "%s %s\n", ti->oid, ti->path);
+
+		pfree(buflinkpath.data);
+#else
+
+		/*
+		 * If the platform does not have symbolic links, it should not be
+		 * possible to have tablespaces - clearly somebody else created them.
+		 * Warn about it and ignore.
+		 */
+		ereport(WARNING,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("tablespaces are not supported on this platform")));
+#endif
+	}
+	FreeDir(tblspcdir);
+}
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index ca074d59ac9..abc3bad01ee 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -67,6 +67,8 @@ static int64 _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *sta
 static void send_int8_string(StringInfoData *buf, int64 intval);
 static void SendBackupHeader(List *tablespaces);
 static void perform_base_backup(basebackup_options *opt);
+static List *collect_wal_files(XLogRecPtr startptr, XLogRecPtr endptr,
+							   List **historyFileList);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
 static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
@@ -438,115 +440,16 @@ perform_base_backup(basebackup_options *opt)
 		 */
 		char		pathbuf[MAXPGPATH];
 		XLogSegNo	segno;
-		XLogSegNo	startsegno;
-		XLogSegNo	endsegno;
 		struct stat statbuf;
 		List	   *historyFileList = NIL;
 		List	   *walFileList = NIL;
-		char		firstoff[MAXFNAMELEN];
-		char		lastoff[MAXFNAMELEN];
-		DIR		   *dir;
-		struct dirent *de;
 		ListCell   *lc;
 		TimeLineID	tli;
 
 		pgstat_progress_update_param(PROGRESS_BASEBACKUP_PHASE,
 									 PROGRESS_BASEBACKUP_PHASE_TRANSFER_WAL);
 
-		/*
-		 * I'd rather not worry about timelines here, so scan pg_wal and
-		 * include all WAL files in the range between 'startptr' and 'endptr',
-		 * regardless of the timeline the file is stamped with. If there are
-		 * some spurious WAL files belonging to timelines that don't belong in
-		 * this server's history, they will be included too. Normally there
-		 * shouldn't be such files, but if there are, there's little harm in
-		 * including them.
-		 */
-		XLByteToSeg(startptr, startsegno, wal_segment_size);
-		XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
-		XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
-		XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
-
-		dir = AllocateDir("pg_wal");
-		while ((de = ReadDir(dir, "pg_wal")) != NULL)
-		{
-			/* Does it look like a WAL segment, and is it in the range? */
-			if (IsXLogFileName(de->d_name) &&
-				strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
-				strcmp(de->d_name + 8, lastoff + 8) <= 0)
-			{
-				walFileList = lappend(walFileList, pstrdup(de->d_name));
-			}
-			/* Does it look like a timeline history file? */
-			else if (IsTLHistoryFileName(de->d_name))
-			{
-				historyFileList = lappend(historyFileList, pstrdup(de->d_name));
-			}
-		}
-		FreeDir(dir);
-
-		/*
-		 * Before we go any further, check that none of the WAL segments we
-		 * need were removed.
-		 */
-		CheckXLogRemoved(startsegno, ThisTimeLineID);
-
-		/*
-		 * Sort the WAL filenames.  We want to send the files in order from
-		 * oldest to newest, to reduce the chance that a file is recycled
-		 * before we get a chance to send it over.
-		 */
-		list_sort(walFileList, compareWalFileNames);
-
-		/*
-		 * There must be at least one xlog file in the pg_wal directory, since
-		 * we are doing backup-including-xlog.
-		 */
-		if (walFileList == NIL)
-			ereport(ERROR,
-					(errmsg("could not find any WAL files")));
-
-		/*
-		 * Sanity check: the first and last segment should cover startptr and
-		 * endptr, with no gaps in between.
-		 */
-		XLogFromFileName((char *) linitial(walFileList),
-						 &tli, &segno, wal_segment_size);
-		if (segno != startsegno)
-		{
-			char		startfname[MAXFNAMELEN];
-
-			XLogFileName(startfname, ThisTimeLineID, startsegno,
-						 wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", startfname)));
-		}
-		foreach(lc, walFileList)
-		{
-			char	   *walFileName = (char *) lfirst(lc);
-			XLogSegNo	currsegno = segno;
-			XLogSegNo	nextsegno = segno + 1;
-
-			XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
-			if (!(nextsegno == segno || currsegno == segno))
-			{
-				char		nextfname[MAXFNAMELEN];
-
-				XLogFileName(nextfname, ThisTimeLineID, nextsegno,
-							 wal_segment_size);
-				ereport(ERROR,
-						(errmsg("could not find WAL file \"%s\"", nextfname)));
-			}
-		}
-		if (segno != endsegno)
-		{
-			char		endfname[MAXFNAMELEN];
-
-			XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
-			ereport(ERROR,
-					(errmsg("could not find WAL file \"%s\"", endfname)));
-		}
-
+		walFileList = collect_wal_files(startptr, endptr, &historyFileList);
 		/* Ok, we have everything we need. Send the WAL files. */
 		foreach(lc, walFileList)
 		{
@@ -681,6 +584,120 @@ perform_base_backup(basebackup_options *opt)
 	pgstat_progress_end_command();
 }
 
+/*
+ * construct a list of WAL files to be included in the backup.
+ */
+static List *
+collect_wal_files(XLogRecPtr startptr, XLogRecPtr endptr, List **historyFileList)
+{
+	XLogSegNo	segno;
+	XLogSegNo	startsegno;
+	XLogSegNo	endsegno;
+	List	   *walFileList = NIL;
+	char		firstoff[MAXFNAMELEN];
+	char		lastoff[MAXFNAMELEN];
+	DIR		   *dir;
+	struct dirent *de;
+	ListCell   *lc;
+	TimeLineID	tli;
+
+	/*
+	 * I'd rather not worry about timelines here, so scan pg_wal and include
+	 * all WAL files in the range between 'startptr' and 'endptr', regardless
+	 * of the timeline the file is stamped with. If there are some spurious
+	 * WAL files belonging to timelines that don't belong in this server's
+	 * history, they will be included too. Normally there shouldn't be such
+	 * files, but if there are, there's little harm in including them.
+	 */
+	XLByteToSeg(startptr, startsegno, wal_segment_size);
+	XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size);
+	XLByteToPrevSeg(endptr, endsegno, wal_segment_size);
+	XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size);
+
+	dir = AllocateDir("pg_wal");
+	while ((de = ReadDir(dir, "pg_wal")) != NULL)
+	{
+		/* Does it look like a WAL segment, and is it in the range? */
+		if (IsXLogFileName(de->d_name) &&
+			strcmp(de->d_name + 8, firstoff + 8) >= 0 &&
+			strcmp(de->d_name + 8, lastoff + 8) <= 0)
+		{
+			walFileList = lappend(walFileList, pstrdup(de->d_name));
+		}
+		/* Does it look like a timeline history file? */
+		else if (IsTLHistoryFileName(de->d_name))
+		{
+			if (historyFileList)
+				*historyFileList = lappend(*historyFileList, pstrdup(de->d_name));
+		}
+	}
+	FreeDir(dir);
+
+	/*
+	 * Before we go any further, check that none of the WAL segments we need
+	 * were removed.
+	 */
+	CheckXLogRemoved(startsegno, ThisTimeLineID);
+
+	/*
+	 * Sort the WAL filenames.  We want to send the files in order from oldest
+	 * to newest, to reduce the chance that a file is recycled before we get a
+	 * chance to send it over.
+	 */
+	list_sort(walFileList, compareWalFileNames);
+
+	/*
+	 * There must be at least one xlog file in the pg_wal directory, since we
+	 * are doing backup-including-xlog.
+	 */
+	if (walFileList == NIL)
+		ereport(ERROR,
+				(errmsg("could not find any WAL files")));
+
+	/*
+	 * Sanity check: the first and last segment should cover startptr and
+	 * endptr, with no gaps in between.
+	 */
+	XLogFromFileName((char *) linitial(walFileList),
+					 &tli, &segno, wal_segment_size);
+	if (segno != startsegno)
+	{
+		char		startfname[MAXFNAMELEN];
+
+		XLogFileName(startfname, ThisTimeLineID, startsegno,
+					 wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", startfname)));
+	}
+	foreach(lc, walFileList)
+	{
+		char	   *walFileName = (char *) lfirst(lc);
+		XLogSegNo	currsegno = segno;
+		XLogSegNo	nextsegno = segno + 1;
+
+		XLogFromFileName(walFileName, &tli, &segno, wal_segment_size);
+		if (!(nextsegno == segno || currsegno == segno))
+		{
+			char		nextfname[MAXFNAMELEN];
+
+			XLogFileName(nextfname, ThisTimeLineID, nextsegno,
+						 wal_segment_size);
+			ereport(ERROR,
+					(errmsg("could not find WAL file \"%s\"", nextfname)));
+		}
+	}
+	if (segno != endsegno)
+	{
+		char		endfname[MAXFNAMELEN];
+
+		XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size);
+		ereport(ERROR,
+				(errmsg("could not find WAL file \"%s\"", endfname)));
+	}
+
+	return walFileList;
+}
+
 /*
  * list_sort comparison function, to compare log/seg portion of WAL segment
  * filenames, ignoring the timeline portion.
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 98b033fc208..22fe35801dc 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -350,6 +350,8 @@ extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
 extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
 									TimeLineID *stoptli_p);
 extern void do_pg_abort_backup(int code, Datum arg);
+extern void collect_tablespaces(List **tablespaces, StringInfo tblspcmapfile,
+								bool infotbssize, bool needtblspcmapfile);
 extern void register_persistent_abort_backup_handler(void);
 extern SessionBackupState get_backup_status(void);
 
-- 
2.21.1 (Apple Git-122.3)

0003-Parallel-Backup-Backend-Replication-commands_v9.patchapplication/octet-stream; name=0003-Parallel-Backup-Backend-Replication-commands_v9.patchDownload
From ab91e2c9078bfe42fb9306314304c558a41b7632 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Mon, 27 Jan 2020 18:32:42 +0500
Subject: [PATCH 3/6] Parallel Backup - Backend Replication commands

This feature adds following replication commands to the backend replication
system, to help facilitate taking a full backup in parallel using multiple
connections.

	- START_BACKUP [LABEL '<label>'] [FAST]
	This command instructs the server to get prepared for performing an
	online backup.

	- STOP_BACKUP [NOWAIT]
	This command instructs the server that online backup is finished. It
	will bring the system out of backup mode.

	- LIST_TABLESPACES [PROGRESS]
	This command instructs the server to return a list of tablespaces.

	- LIST_FILES [TABLESPACE]
	This command instructs the server to return a list of files for a
	given tablespace, base tablespace if TABLESPACE is empty.

	- LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
	This command instructs the server to return a list WAL files between
	the given locations.

	- SEND_FILES '(' FILE, FILE... ')' [START_WAL_LOCATION 'X/X']
			[NOVERIFY_CHECKSUMS]
	Instructs the server to send the contents of the requested FILE(s).
---
 src/backend/access/transam/xlog.c      |   4 +-
 src/backend/replication/basebackup.c   | 529 ++++++++++++++++++++++++-
 src/backend/replication/repl_gram.y    | 265 +++++++++++--
 src/backend/replication/repl_scanner.l |   8 +
 src/include/nodes/replnodes.h          |  12 +
 src/include/replication/basebackup.h   |   2 +-
 6 files changed, 751 insertions(+), 69 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f5670141126..4189b056c88 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -11128,7 +11128,7 @@ do_pg_abort_backup(int code, Datum arg)
 
 	if (emit_warning)
 		ereport(WARNING,
-				(errmsg("aborting backup due to backend exiting before pg_stop_back up was called")));
+				(errmsg("aborting backup due to backend exiting while a non-exclusive backup is in progress")));
 }
 
 /*
@@ -12377,7 +12377,7 @@ collect_tablespaces(List **tablespaces, StringInfo tblspcmapfile,
 		ti->oid = pstrdup(de->d_name);
 		ti->path = pstrdup(buflinkpath.data);
 		ti->rpath = relpath ? pstrdup(relpath) : NULL;
-		ti->size = infotbssize ? sendTablespace(fullpath, true) : -1;
+		ti->size = infotbssize ? sendTablespace(fullpath, true, NULL) : -1;
 
 		if (tablespaces)
 			*tablespaces = lappend(*tablespaces, ti);
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index abc3bad01ee..a294d77da50 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -39,6 +39,8 @@
 #include "storage/ipc.h"
 #include "storage/reinit.h"
 #include "utils/builtins.h"
+#include "utils/memutils.h"
+#include "utils/pg_lsn.h"
 #include "utils/ps_status.h"
 #include "utils/relcache.h"
 #include "utils/timestamp.h"
@@ -52,11 +54,22 @@ typedef struct
 	bool		includewal;
 	uint32		maxrate;
 	bool		sendtblspcmapfile;
+	XLogRecPtr	startwallocation;
+	XLogRecPtr	endwallocation;
+	char	   *tablespace;
 } basebackup_options;
 
+typedef struct
+{
+	char		path[MAXPGPATH];
+	char		type;
+	size_t		size;
+	time_t		mtime;
+} BackupFile;
+
 
 static int64 sendDir(const char *path, int basepathlen, bool dryrun,
-					 List *tablespaces, bool sendtblspclinks);
+					 List *tablespaces, bool sendtblspclinks, List **filelist);
 static bool sendFile(const char *readfilename, const char *tarfilename,
 					 struct stat *statbuf, bool missing_ok, Oid dboid);
 static void sendFileWithContent(const char *filename, const char *content);
@@ -70,12 +83,28 @@ static void perform_base_backup(basebackup_options *opt);
 static List *collect_wal_files(XLogRecPtr startptr, XLogRecPtr endptr,
 							   List **historyFileList);
 static void parse_basebackup_options(List *options, basebackup_options *opt);
-static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli);
+static void SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli, StringInfo label);
+static void SendFilesHeader(List *files);
 static int	compareWalFileNames(const ListCell *a, const ListCell *b);
 static void throttle(size_t increment);
 static void update_basebackup_progress(int64 delta);
 static bool is_checksummed_file(const char *fullpath, const char *filename);
 
+static void start_backup(basebackup_options *opt);
+static void stop_backup(basebackup_options *opt);
+static void list_tablespaces(basebackup_options *opt);
+static void list_files(basebackup_options *opt);
+static void list_wal_files(basebackup_options *opt);
+static void send_files(basebackup_options *opt, List *filenames,
+					   bool missing_ok);
+static void add_to_filelist(List **filelist, char *path, char type,
+							size_t size, time_t mtime);
+
+/*
+ * Store label file during non-exclusive backups.
+ */
+static StringInfo label_file;
+
 /* Was the backup currently in-progress initiated in recovery mode? */
 static bool backup_started_in_recovery = false;
 
@@ -303,7 +332,7 @@ perform_base_backup(basebackup_options *opt)
 
 		/* Add a node for the base directory at the end */
 		ti = palloc0(sizeof(tablespaceinfo));
-		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true) : -1;
+		ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
 		tablespaces = lappend(tablespaces, ti);
 
 		/*
@@ -336,7 +365,7 @@ perform_base_backup(basebackup_options *opt)
 		}
 
 		/* Send the starting position of the backup */
-		SendXlogRecPtrResult(startptr, starttli);
+		SendXlogRecPtrResult(startptr, starttli, NULL);
 
 		/* Send tablespace header */
 		SendBackupHeader(tablespaces);
@@ -391,10 +420,10 @@ perform_base_backup(basebackup_options *opt)
 				if (tblspc_map_file && opt->sendtblspcmapfile)
 				{
 					sendFileWithContent(TABLESPACE_MAP, tblspc_map_file->data);
-					sendDir(".", 1, false, tablespaces, false);
+					sendDir(".", 1, false, tablespaces, false, NULL);
 				}
 				else
-					sendDir(".", 1, false, tablespaces, true);
+					sendDir(".", 1, false, tablespaces, true, NULL);
 
 				/* ... and pg_control after everything else. */
 				if (lstat(XLOG_CONTROL_FILE, &statbuf) != 0)
@@ -405,7 +434,7 @@ perform_base_backup(basebackup_options *opt)
 				sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false, InvalidOid);
 			}
 			else
-				sendTablespace(ti->path, false);
+				sendTablespace(ti->path, false, NULL);
 
 			/*
 			 * If we're including WAL, and this is the main data directory we
@@ -568,7 +597,7 @@ perform_base_backup(basebackup_options *opt)
 		/* Send CopyDone message for the last tar file */
 		pq_putemptymessage('c');
 	}
-	SendXlogRecPtrResult(endptr, endtli);
+	SendXlogRecPtrResult(endptr, endtli, NULL);
 
 	if (total_checksum_failures)
 	{
@@ -726,6 +755,9 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 	bool		o_maxrate = false;
 	bool		o_tablespace_map = false;
 	bool		o_noverify_checksums = false;
+	bool		o_startwallocation = false;
+	bool		o_endwallocation = false;
+	bool		o_tablespace = false;
 
 	MemSet(opt, 0, sizeof(*opt));
 	foreach(lopt, options)
@@ -814,12 +846,47 @@ parse_basebackup_options(List *options, basebackup_options *opt)
 			noverify_checksums = true;
 			o_noverify_checksums = true;
 		}
+		else if (strcmp(defel->defname, "start_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *startwallocation;
+
+			if (o_startwallocation)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			startwallocation = strVal(defel->arg);
+			opt->startwallocation = pg_lsn_in_internal(startwallocation, &have_error);
+			o_startwallocation = true;
+		}
+		else if (strcmp(defel->defname, "end_wal_location") == 0)
+		{
+			bool		have_error = false;
+			char	   *endwallocation;
+
+			if (o_endwallocation)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+
+			endwallocation = strVal(defel->arg);
+			opt->endwallocation = pg_lsn_in_internal(endwallocation, &have_error);
+			o_endwallocation = true;
+		}
+		else if (strcmp(defel->defname, "tablespace") == 0)
+		{
+			if (o_tablespace)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("duplicate option \"%s\"", defel->defname)));
+			opt->tablespace = strVal(defel->arg);
+			o_tablespace = true;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
 	}
-	if (opt->label == NULL)
-		opt->label = "base backup";
 }
 
 
@@ -837,6 +904,15 @@ SendBaseBackup(BaseBackupCmd *cmd)
 
 	parse_basebackup_options(cmd->options, &opt);
 
+	/* default value for label, if not specified. */
+	if (opt.label == NULL)
+	{
+		if (cmd->cmdtag == BASE_BACKUP)
+			opt.label = "base backup";
+		else
+			opt.label = "start backup";
+	}
+
 	WalSndSetState(WALSNDSTATE_BACKUP);
 
 	if (update_process_title)
@@ -848,7 +924,34 @@ SendBaseBackup(BaseBackupCmd *cmd)
 		set_ps_display(activitymsg);
 	}
 
-	perform_base_backup(&opt);
+	switch (cmd->cmdtag)
+	{
+		case BASE_BACKUP:
+			perform_base_backup(&opt);
+			break;
+		case START_BACKUP:
+			start_backup(&opt);
+			break;
+		case LIST_TABLESPACES:
+			list_tablespaces(&opt);
+			break;
+		case LIST_FILES:
+			list_files(&opt);
+			break;
+		case SEND_FILES:
+			send_files(&opt, cmd->backupfiles, true);
+			break;
+		case STOP_BACKUP:
+			stop_backup(&opt);
+			break;
+		case LIST_WAL_FILES:
+			list_wal_files(&opt);
+			break;
+		default:
+			elog(ERROR, "unrecognized replication command tag: %u",
+				 cmd->cmdtag);
+			break;
+	}
 }
 
 static void
@@ -936,18 +1039,18 @@ SendBackupHeader(List *tablespaces)
 }
 
 /*
- * Send a single resultset containing just a single
- * XLogRecPtr record (in text format)
+ * Send a single resultset containing XLogRecPtr record (in text format)
+ * TimelineID and backup label.
  */
 static void
-SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
+SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli, StringInfo label)
 {
 	StringInfoData buf;
 	char		str[MAXFNAMELEN];
 	Size		len;
 
 	pq_beginmessage(&buf, 'T'); /* RowDescription */
-	pq_sendint16(&buf, 2);		/* 2 fields */
+	pq_sendint16(&buf, 3);		/* 3 fields */
 
 	/* Field headers */
 	pq_sendstring(&buf, "recptr");
@@ -970,11 +1073,19 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_sendint16(&buf, -1);
 	pq_sendint32(&buf, 0);
 	pq_sendint16(&buf, 0);
+
+	pq_sendstring(&buf, "label");
+	pq_sendint32(&buf, 0);		/* table oid */
+	pq_sendint16(&buf, 0);		/* attnum */
+	pq_sendint32(&buf, TEXTOID);	/* type oid */
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
 	pq_endmessage(&buf);
 
 	/* Data row */
 	pq_beginmessage(&buf, 'D');
-	pq_sendint16(&buf, 2);		/* number of columns */
+	pq_sendint16(&buf, 3);		/* number of columns */
 
 	len = snprintf(str, sizeof(str),
 				   "%X/%X", (uint32) (ptr >> 32), (uint32) ptr);
@@ -985,12 +1096,109 @@ SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
 	pq_sendint32(&buf, len);
 	pq_sendbytes(&buf, str, len);
 
+	if (label)
+	{
+		len = label->len;
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, label->data, len);
+	}
+	else
+	{
+		pq_sendint32(&buf, -1); /* NULL */
+	}
+
 	pq_endmessage(&buf);
 
 	/* Send a CommandComplete message */
 	pq_puttextmessage('C', "SELECT");
 }
 
+
+/*
+ * Sends the resultset containing filename, type (where type can be f' for
+ * regular, 'd' for directory, 'l' for link), file size and modification time).
+ */
+static void
+SendFilesHeader(List *files)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+
+	/* Construct and send the list of files */
+
+	pq_beginmessage(&buf, 'T'); /* RowDescription */
+	pq_sendint16(&buf, 4);		/* n field */
+
+	/* First field - file name */
+	pq_sendstring(&buf, "path");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, TEXTOID);
+	pq_sendint16(&buf, -1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	/* Second field - is_dir */
+	pq_sendstring(&buf, "type");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, CHAROID);
+	pq_sendint16(&buf, 1);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	/* Third field - size */
+	pq_sendstring(&buf, "size");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, INT8OID);
+	pq_sendint16(&buf, 8);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+
+	/* Fourth field - mtime */
+	pq_sendstring(&buf, "mtime");
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_sendint32(&buf, INT8OID);
+	pq_sendint16(&buf, 8);
+	pq_sendint32(&buf, 0);
+	pq_sendint16(&buf, 0);
+	pq_endmessage(&buf);
+
+	foreach(lc, files)
+	{
+		BackupFile *file = (BackupFile *) lfirst(lc);
+		Size		len;
+
+		/* Send one datarow message */
+		pq_beginmessage(&buf, 'D');
+		pq_sendint16(&buf, 4);	/* number of columns */
+
+		/* send path */
+		len = strlen(file->path);
+		pq_sendint32(&buf, len);
+		pq_sendbytes(&buf, file->path, len);
+
+		/* send type */
+		pq_sendint32(&buf, 1);
+		pq_sendbyte(&buf, file->type);
+
+		/* send size */
+		send_int8_string(&buf, file->size);
+
+		/* send mtime */
+		send_int8_string(&buf, file->mtime);
+
+		pq_endmessage(&buf);
+	}
+
+	list_free(files);
+
+	/* Send a CommandComplete message */
+	pq_puttextmessage('C', "SELECT");
+}
+
 /*
  * Inject a file with given name and content in the output tar stream.
  */
@@ -1044,7 +1252,7 @@ sendFileWithContent(const char *filename, const char *content)
  * Only used to send auxiliary tablespaces, not PGDATA.
  */
 int64
-sendTablespace(char *path, bool dryrun)
+sendTablespace(char *path, bool dryrun, List **filelist)
 {
 	int64		size;
 	char		pathbuf[MAXPGPATH];
@@ -1073,11 +1281,11 @@ sendTablespace(char *path, bool dryrun)
 		return 0;
 	}
 
+	add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 	size = _tarWriteHeader(TABLESPACE_VERSION_DIRECTORY, NULL, &statbuf,
 						   dryrun);
-
 	/* Send all the files in the tablespace version directory */
-	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true);
+	size += sendDir(pathbuf, strlen(path), dryrun, NIL, true, filelist);
 
 	return size;
 }
@@ -1096,7 +1304,7 @@ sendTablespace(char *path, bool dryrun)
  */
 static int64
 sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
-		bool sendtblspclinks)
+		bool sendtblspclinks, List **filelist)
 {
 	DIR		   *dir;
 	struct dirent *de;
@@ -1254,6 +1462,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			if (strcmp(de->d_name, excludeDirContents[excludeIdx]) == 0)
 			{
 				elog(DEBUG1, "contents of directory \"%s\" excluded from backup", de->d_name);
+
+				add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 				size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 				excludeFound = true;
 				break;
@@ -1270,6 +1480,8 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 		if (statrelpath != NULL && strcmp(pathbuf, statrelpath) == 0)
 		{
 			elog(DEBUG1, "contents of directory \"%s\" excluded from backup", statrelpath);
+
+			add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 			size += _tarWriteDir(pathbuf, basepathlen, &statbuf, dryrun);
 			continue;
 		}
@@ -1291,6 +1503,10 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			size += _tarWriteHeader("./pg_wal/archive_status", NULL, &statbuf,
 									dryrun);
 
+			add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
+			add_to_filelist(filelist, "./pg_wal/archive_status", 'd', -1,
+							statbuf.st_mtime);
+
 			continue;			/* don't recurse into pg_wal */
 		}
 
@@ -1320,6 +1536,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 								pathbuf)));
 			linkpath[rllen] = '\0';
 
+			add_to_filelist(filelist, pathbuf, 'l', statbuf.st_size, statbuf.st_mtime);
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, linkpath,
 									&statbuf, dryrun);
 #else
@@ -1346,6 +1563,7 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 			 */
 			size += _tarWriteHeader(pathbuf + basepathlen + 1, NULL, &statbuf,
 									dryrun);
+			add_to_filelist(filelist, pathbuf, 'd', -1, statbuf.st_mtime);
 
 			/*
 			 * Call ourselves recursively for a directory, unless it happens
@@ -1376,13 +1594,15 @@ sendDir(const char *path, int basepathlen, bool dryrun, List *tablespaces,
 				skip_this_dir = true;
 
 			if (!skip_this_dir)
-				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks);
+				size += sendDir(pathbuf, basepathlen, dryrun, tablespaces, sendtblspclinks, filelist);
 		}
 		else if (S_ISREG(statbuf.st_mode))
 		{
 			bool		sent = false;
 
-			if (!dryrun)
+			add_to_filelist(filelist, pathbuf, 'f', statbuf.st_size, statbuf.st_mtime);
+
+			if (!dryrun && filelist == NULL)
 				sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
 								true, isDbDir ? atooid(lastDir + 1) : InvalidOid);
 
@@ -1867,3 +2087,268 @@ update_basebackup_progress(int64 delta)
 
 	pgstat_progress_update_multi_param(nparam, index, val);
 }
+
+/*
+ * start_backup - prepare to start an online backup.
+ *
+ * This function calls do_pg_start_backup() and sends back starting checkpoint,
+ * available tablespaces, content of backup_label and tablespace_map files.
+ */
+static void
+start_backup(basebackup_options *opt)
+{
+	TimeLineID	starttli;
+	StringInfo	tblspc_map_file;
+	MemoryContext oldcontext;
+
+	/* Label file need to be long-lived, since its read in stop_backup. */
+	oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+	label_file = makeStringInfo();
+	MemoryContextSwitchTo(oldcontext);
+
+	/*
+	 * tablespace map file is not used, but since this argument is required by
+	 * do_pg_start_backup, we have to provide it here.
+	 */
+	tblspc_map_file = makeStringInfo();
+
+	register_persistent_abort_backup_handler();
+	startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint, &starttli,
+								  label_file, NULL, tblspc_map_file, false, false);
+
+	/* send startptr and starttli to frontend */
+	SendXlogRecPtrResult(startptr, starttli, NULL);
+
+	/* free tablspace map buffer. */
+	pfree(tblspc_map_file->data);
+	pfree(tblspc_map_file);
+}
+
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */
+static void
+stop_backup(basebackup_options *opt)
+{
+	TimeLineID	endtli;
+	XLogRecPtr	endptr;
+
+	if (get_backup_status() != SESSION_BACKUP_NON_EXCLUSIVE)
+		ereport(ERROR,
+				(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				 errmsg("non-exclusive backup is not in progress")));
+
+	/*
+	 * Stop the non-exclusive backup. Return a copy of the backup label so it
+	 * can be written to disk by the caller.
+	 */
+	endptr = do_pg_stop_backup(label_file->data, !opt->nowait, &endtli);
+	SendXlogRecPtrResult(endptr, endtli, label_file);
+
+	/* Free structures allocated in TopMemoryContext */
+	pfree(label_file->data);
+	pfree(label_file);
+	label_file = NULL;
+}
+
+/*
+ * list_tablespaces() - sends a list of tablespace entries
+ */
+static void
+list_tablespaces(basebackup_options *opt)
+{
+	StringInfo	tblspc_map_file;
+	List	   *tablespaces = NIL;
+	tablespaceinfo *ti;
+
+	tblspc_map_file = makeStringInfo();
+	collect_tablespaces(&tablespaces, tblspc_map_file, opt->progress, false);
+
+	/* Add a node for the base directory at the end */
+	ti = palloc0(sizeof(tablespaceinfo));
+	ti->size = opt->progress ? sendDir(".", 1, true, tablespaces, true, NULL) : -1;
+	tablespaces = lappend(tablespaces, ti);
+
+	SendBackupHeader(tablespaces);
+	list_free(tablespaces);
+}
+
+/*
+ * list_files() - sends a list of files available in given tablespace.
+ */
+static void
+list_files(basebackup_options *opt)
+{
+	List	   *files = NIL;
+	int			datadirpathlen;
+
+	datadirpathlen = strlen(DataDir);
+
+	/*
+	 * Calculate the relative path of temporary statistics directory in order
+	 * to skip the files which are located in that directory later.
+	 */
+	if (is_absolute_path(pgstat_stat_directory) &&
+		strncmp(pgstat_stat_directory, DataDir, datadirpathlen) == 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory + datadirpathlen + 1);
+	else if (strncmp(pgstat_stat_directory, "./", 2) != 0)
+		statrelpath = psprintf("./%s", pgstat_stat_directory);
+	else
+		statrelpath = pgstat_stat_directory;
+
+	if (strlen(opt->tablespace) > 0)
+		sendTablespace(opt->tablespace, true, &files);
+	else
+		sendDir(".", 1, true, NIL, true, &files);
+
+	SendFilesHeader(files);
+}
+
+/*
+ * list_wal_files() - sends a list of WAL files between start wal location and
+ * end wal location.
+ */
+static void
+list_wal_files(basebackup_options *opt)
+{
+	List	   *historyFileList = NIL;
+	List	   *walFileList = NIL;
+	List	   *files = NIL;
+	ListCell   *lc;
+
+	walFileList = collect_wal_files(opt->startwallocation, opt->endwallocation,
+									&historyFileList);
+	foreach(lc, walFileList)
+	{
+		char		pathbuf[MAXPGPATH];
+		char	   *walFileName = (char *) lfirst(lc);
+
+		snprintf(pathbuf, MAXPGPATH, XLOGDIR "/%s", walFileName);
+		add_to_filelist(&files, pathbuf, 'f', wal_segment_size, 0);
+	}
+
+	SendFilesHeader(files);
+}
+
+/*
+ * send_files() - sends the actual files to the caller
+ *
+ * The function sends out the given file(s) over to the caller using the COPY
+ * protocol. It does only entertains the regular files and any other kind such
+ * as directories or symlink etc will be ignored.
+ */
+static void
+send_files(basebackup_options *opt, List *filenames, bool missing_ok)
+{
+	StringInfoData buf;
+	ListCell   *lc;
+	int			basepathlen = 0;
+
+	if (list_length(filenames) <= 0)
+		return;
+
+	total_checksum_failures = 0;
+
+	/* Disable throttling. */
+	throttling_counter = -1;
+
+	/* set backup start location. */
+	startptr = opt->startwallocation;
+
+	/* Send CopyOutResponse message */
+	pq_beginmessage(&buf, 'H');
+	pq_sendbyte(&buf, 0);		/* overall format */
+	pq_sendint16(&buf, 0);		/* natts */
+	pq_endmessage(&buf);
+
+	foreach(lc, filenames)
+	{
+		struct stat statbuf;
+		char	   *pathbuf;
+
+		pathbuf = (char *) strVal(lfirst(lc));
+		if (is_absolute_path(pathbuf))
+		{
+			char	   *basepath;
+
+			/*
+			 * 'pathbuf' points to the tablespace location, but we only want
+			 * to include the version directory in it that belongs to us.
+			 */
+			basepath = strstr(pathbuf, TABLESPACE_VERSION_DIRECTORY);
+			if (basepath)
+				basepathlen = basepath - pathbuf - 1;
+		}
+		else if (pathbuf[0] == '.' && pathbuf[1] == '/')
+			basepathlen = 2;
+		else
+			basepathlen = 0;
+
+		if (lstat(pathbuf, &statbuf) != 0)
+		{
+			if (errno != ENOENT)
+				ereport(ERROR,
+						(errcode_for_file_access(),
+						 errmsg("could not stat file or directory \"%s\": %m",
+								pathbuf)));
+
+			/* If the file went away while scanning, it's not an error. */
+			continue;
+		}
+
+		/*
+		 * Only entertain requests for regular file, skip any directories or
+		 * special files.
+		 */
+		if (S_ISREG(statbuf.st_mode))
+		{
+			/* send file to client */
+			sendFile(pathbuf, pathbuf + basepathlen, &statbuf, true, InvalidOid);
+		}
+		else
+			ereport(WARNING,
+					(errmsg("skipping special file or directory \"%s\"", pathbuf)));
+	}
+
+	pq_putemptymessage('c');	/* CopyDone */
+
+	/*
+	 * Check for checksum failures. If there are failures across multiple
+	 * processes it may not report total checksum count, but it will error
+	 * out,terminating the backup.
+	 */
+	if (total_checksum_failures)
+	{
+		if (total_checksum_failures > 1)
+			ereport(WARNING,
+					(errmsg("%lld total checksum verification failures", total_checksum_failures)));
+
+		ereport(ERROR,
+				(errcode(ERRCODE_DATA_CORRUPTED),
+				 errmsg("checksum verification failure during base backup")));
+	}
+}
+
+/*
+ * Construct a BackupFile entry and add to the list.
+ */
+static void
+add_to_filelist(List **filelist, char *path, char type, size_t size,
+				time_t mtime)
+{
+	BackupFile *file;
+
+	if (filelist)
+	{
+		file = (BackupFile *) palloc(sizeof(BackupFile));
+		strlcpy(file->path, path, sizeof(file->path));
+		file->type = type;
+		file->size = size;
+		file->mtime = mtime;
+
+		*filelist = lappend(*filelist, file);
+	}
+}
diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y
index 14fcd532218..16e5402d55d 100644
--- a/src/backend/replication/repl_gram.y
+++ b/src/backend/replication/repl_gram.y
@@ -87,13 +87,28 @@ static SQLCmd *make_sqlcmd(void);
 %token K_EXPORT_SNAPSHOT
 %token K_NOEXPORT_SNAPSHOT
 %token K_USE_SNAPSHOT
+%token K_START_BACKUP
+%token K_LIST_TABLESPACES
+%token K_LIST_FILES
+%token K_SEND_FILES
+%token K_STOP_BACKUP
+%token K_LIST_WAL_FILES
+%token K_START_WAL_LOCATION
+%token K_END_WAL_LOCATION
 
 %type <node>	command
 %type <node>	base_backup start_replication start_logical_replication
 				create_replication_slot drop_replication_slot identify_system
 				timeline_history show sql_cmd
-%type <list>	base_backup_opt_list
-%type <defelt>	base_backup_opt
+%type <list>	base_backup_opt_list start_backup_opt_list stop_backup_opt_list
+				list_tablespace_opt_list list_files_opt_list
+				list_wal_files_opt_list send_backup_files_opt_list
+				backup_files backup_files_list
+%type <defelt>	base_backup_opt backup_opt_label backup_opt_progress
+				backup_opt_fast backup_opt_wal backup_opt_nowait
+				backup_opt_maxrate backup_opt_tsmap backup_opt_chksum
+				backup_opt_start_wal_loc backup_opt_end_wal_loc
+				backup_opt_tablespace start_backup_opt send_backup_files_opt
 %type <uintval>	opt_timeline
 %type <list>	plugin_options plugin_opt_list
 %type <defelt>	plugin_opt_elem
@@ -153,69 +168,231 @@ var_name:	IDENT	{ $$ = $1; }
 				{ $$ = psprintf("%s.%s", $1, $3); }
 		;
 
-/*
- * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
- * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS]
- */
 base_backup:
+			/*
+			 * BASE_BACKUP [LABEL '<label>'] [PROGRESS] [FAST] [WAL] [NOWAIT]
+			 * [MAX_RATE %d] [TABLESPACE_MAP] [NOVERIFY_CHECKSUMS]
+			 */
 			K_BASE_BACKUP base_backup_opt_list
 				{
 					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
 					cmd->options = $2;
+					cmd->cmdtag = BASE_BACKUP;
 					$$ = (Node *) cmd;
 				}
-			;
-
-base_backup_opt_list:
-			base_backup_opt_list base_backup_opt
-				{ $$ = lappend($1, $2); }
-			| /* EMPTY */
-				{ $$ = NIL; }
-			;
-
-base_backup_opt:
-			K_LABEL SCONST
-				{
-				  $$ = makeDefElem("label",
-								   (Node *)makeString($2), -1);
-				}
-			| K_PROGRESS
+			 /* START_BACKUP [LABEL '<label>'] [FAST] */
+			| K_START_BACKUP start_backup_opt_list
 				{
-				  $$ = makeDefElem("progress",
-								   (Node *)makeInteger(true), -1);
-				}
-			| K_FAST
-				{
-				  $$ = makeDefElem("fast",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = START_BACKUP;
+					$$ = (Node *) cmd;
 				}
-			| K_WAL
+			/* STOP_BACKUP [NOWAIT] */
+			| K_STOP_BACKUP stop_backup_opt_list
 				{
-				  $$ = makeDefElem("wal",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = STOP_BACKUP;
+					$$ = (Node *) cmd;
 				}
-			| K_NOWAIT
+			/* LIST_TABLESPACES [PROGRESS] */
+			| K_LIST_TABLESPACES list_tablespace_opt_list
 				{
-				  $$ = makeDefElem("nowait",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = LIST_TABLESPACES;
+					$$ = (Node *) cmd;
 				}
-			| K_MAX_RATE UCONST
+			/* LIST_FILES [TABLESPACE] */
+			| K_LIST_FILES list_files_opt_list
 				{
-				  $$ = makeDefElem("max_rate",
-								   (Node *)makeInteger($2), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = LIST_FILES;
+					$$ = (Node *) cmd;
 				}
-			| K_TABLESPACE_MAP
+			/* LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X'] */
+			| K_LIST_WAL_FILES list_wal_files_opt_list
 				{
-				  $$ = makeDefElem("tablespace_map",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $2;
+					cmd->cmdtag = LIST_WAL_FILES;
+					$$ = (Node *) cmd;
 				}
-			| K_NOVERIFY_CHECKSUMS
+			/*
+			 * SEND_FILES '(' 'FILE' [, ...] ')' [START_WAL_LOCATION 'X/X']
+			 *		[NOVERIFY_CHECKSUMS]
+			 */
+			| K_SEND_FILES backup_files send_backup_files_opt_list
 				{
-				  $$ = makeDefElem("noverify_checksums",
-								   (Node *)makeInteger(true), -1);
+					BaseBackupCmd *cmd = makeNode(BaseBackupCmd);
+					cmd->options = $3;
+					cmd->cmdtag = SEND_FILES;
+					cmd->backupfiles = $2;
+					$$ = (Node *) cmd;
 				}
 			;
 
+base_backup_opt_list:
+			base_backup_opt_list base_backup_opt
+				{ $$ = lappend($1, $2); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+base_backup_opt:
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_progress	{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			| backup_opt_wal 		{ $$ = $1; }
+			| backup_opt_nowait		{ $$ = $1; }
+			| backup_opt_maxrate	{ $$ = $1; }
+			| backup_opt_tsmap		{ $$ = $1; }
+			| backup_opt_chksum		{ $$ = $1; }
+			;
+
+start_backup_opt_list:
+			start_backup_opt_list start_backup_opt
+				{ $$ = lappend($1, $2); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+start_backup_opt:
+			backup_opt_label		{ $$ = $1; }
+			| backup_opt_fast		{ $$ = $1; }
+			;
+
+stop_backup_opt_list:
+			backup_opt_nowait
+				{ $$ = list_make1($1); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+list_tablespace_opt_list:
+			backup_opt_progress
+				{ $$ = list_make1($1); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+list_files_opt_list:
+			backup_opt_tablespace
+				{ $$ = list_make1($1); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+list_wal_files_opt_list:
+			backup_opt_start_wal_loc backup_opt_end_wal_loc
+				{ $$ = list_make2($1, $2); }
+			;
+
+send_backup_files_opt_list:
+			send_backup_files_opt_list send_backup_files_opt
+				{ $$ = lappend($1, $2); }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files:
+			'(' backup_files_list ')'
+				{ $$ = $2; }
+			| /* EMPTY */
+				{ $$ = NIL; }
+			;
+
+backup_files_list:
+			SCONST
+				{ $$ = list_make1(makeString($1)); }
+			| backup_files_list ',' SCONST
+				{ $$ = lappend($1, makeString($3)); }
+			;
+
+send_backup_files_opt:
+			backup_opt_chksum		{ $$ = $1; }
+			| backup_opt_start_wal_loc	{ $$ = $1; }
+			;
+
+backup_opt_label:
+	K_LABEL SCONST
+	{
+	  $$ = makeDefElem("label",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_progress:
+	K_PROGRESS
+	{
+	  $$ = makeDefElem("progress",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_fast:
+	K_FAST
+	{
+	  $$ = makeDefElem("fast",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_wal:
+	K_WAL
+	{
+	  $$ = makeDefElem("wal",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_nowait:
+	K_NOWAIT
+	{
+	  $$ = makeDefElem("nowait",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_maxrate:
+	K_MAX_RATE UCONST
+	{
+	  $$ = makeDefElem("max_rate",
+					   (Node *)makeInteger($2), -1);
+	};
+
+backup_opt_tsmap:
+	K_TABLESPACE_MAP
+	{
+	  $$ = makeDefElem("tablespace_map",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_chksum:
+	K_NOVERIFY_CHECKSUMS
+	{
+	  $$ = makeDefElem("noverify_checksums",
+					   (Node *)makeInteger(true), -1);
+	};
+
+backup_opt_start_wal_loc:
+	K_START_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("start_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_end_wal_loc:
+	K_END_WAL_LOCATION SCONST
+	{
+	  $$ = makeDefElem("end_wal_location",
+					   (Node *)makeString($2), -1);
+	};
+
+backup_opt_tablespace:
+	SCONST
+	{
+		$$ = makeDefElem("tablespace", //tblspcname?
+						 (Node *)makeString($1), -1);
+	};
+
 create_replication_slot:
 			/* CREATE_REPLICATION_SLOT slot TEMPORARY PHYSICAL RESERVE_WAL */
 			K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_PHYSICAL create_slot_opt_list
diff --git a/src/backend/replication/repl_scanner.l b/src/backend/replication/repl_scanner.l
index 14c9a1e798a..faa00cfd0ee 100644
--- a/src/backend/replication/repl_scanner.l
+++ b/src/backend/replication/repl_scanner.l
@@ -107,6 +107,14 @@ EXPORT_SNAPSHOT		{ return K_EXPORT_SNAPSHOT; }
 NOEXPORT_SNAPSHOT	{ return K_NOEXPORT_SNAPSHOT; }
 USE_SNAPSHOT		{ return K_USE_SNAPSHOT; }
 WAIT				{ return K_WAIT; }
+START_BACKUP		{ return K_START_BACKUP; }
+LIST_FILES			{ return K_LIST_FILES; }
+LIST_TABLESPACES	{ return K_LIST_TABLESPACES; }
+SEND_FILES			{ return K_SEND_FILES; }
+STOP_BACKUP			{ return K_STOP_BACKUP; }
+LIST_WAL_FILES		{ return K_LIST_WAL_FILES; }
+START_WAL_LOCATION	{ return K_START_WAL_LOCATION; }
+END_WAL_LOCATION	{ return K_END_WAL_LOCATION; }
 
 ","				{ return ','; }
 ";"				{ return ';'; }
diff --git a/src/include/nodes/replnodes.h b/src/include/nodes/replnodes.h
index 5456141a8ab..c046ea39ae9 100644
--- a/src/include/nodes/replnodes.h
+++ b/src/include/nodes/replnodes.h
@@ -23,6 +23,16 @@ typedef enum ReplicationKind
 	REPLICATION_KIND_LOGICAL
 } ReplicationKind;
 
+typedef enum BackupCmdTag
+{
+	BASE_BACKUP,
+	START_BACKUP,
+	LIST_TABLESPACES,
+	LIST_FILES,
+	LIST_WAL_FILES,
+	SEND_FILES,
+	STOP_BACKUP
+} BackupCmdTag;
 
 /* ----------------------
  *		IDENTIFY_SYSTEM command
@@ -42,6 +52,8 @@ typedef struct BaseBackupCmd
 {
 	NodeTag		type;
 	List	   *options;
+	BackupCmdTag cmdtag;
+	List	   *backupfiles;
 } BaseBackupCmd;
 
 
diff --git a/src/include/replication/basebackup.h b/src/include/replication/basebackup.h
index e0210def6f3..3bc85d4c3e2 100644
--- a/src/include/replication/basebackup.h
+++ b/src/include/replication/basebackup.h
@@ -31,6 +31,6 @@ typedef struct
 
 extern void SendBaseBackup(BaseBackupCmd *cmd);
 
-extern int64 sendTablespace(char *path, bool dryrun);
+extern int64 sendTablespace(char *path, bool dryrun, List **filelist);
 
 #endif							/* _BASEBACKUP_H */
-- 
2.21.1 (Apple Git-122.3)

0005-parallel-backup-testcase_v9.patchapplication/octet-stream; name=0005-parallel-backup-testcase_v9.patchDownload
From 04a98b7ca2e824aac6f1d6fcf9b078c83c6a7ca4 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Sun, 13 Oct 2019 21:54:23 +0500
Subject: [PATCH 5/6] parallel backup - testcase

---
 .../t/040_pg_basebackup_parallel.pl           | 527 ++++++++++++++++++
 1 file changed, 527 insertions(+)
 create mode 100644 src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl

diff --git a/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
new file mode 100644
index 00000000000..4ec4c1e0f6b
--- /dev/null
+++ b/src/bin/pg_basebackup/t/040_pg_basebackup_parallel.pl
@@ -0,0 +1,527 @@
+use strict;
+use warnings;
+use Cwd;
+use Config;
+use File::Basename qw(basename dirname);
+use File::Path qw(rmtree);
+use PostgresNode;
+use TestLib;
+use Test::More tests => 95;
+
+program_help_ok('pg_basebackup');
+program_version_ok('pg_basebackup');
+program_options_handling_ok('pg_basebackup');
+
+my $tempdir = TestLib::tempdir;
+
+my $node = get_new_node('main');
+
+# Set umask so test directories and files are created with default permissions
+umask(0077);
+
+# Initialize node without replication settings
+$node->init(extra => ['--data-checksums']);
+$node->start;
+my $pgdata = $node->data_dir;
+
+$node->command_fails(['pg_basebackup'],
+	'pg_basebackup needs target directory specified');
+
+# Some Windows ANSI code pages may reject this filename, in which case we
+# quietly proceed without this bit of test coverage.
+if (open my $badchars, '>>', "$tempdir/pgdata/FOO\xe0\xe0\xe0BAR")
+{
+	print $badchars "test backup of file with non-UTF8 name\n";
+	close $badchars;
+}
+
+$node->set_replication_conf();
+system_or_bail 'pg_ctl', '-D', $pgdata, 'reload';
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup" ],
+	'pg_basebackup fails because of WAL configuration');
+
+ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
+
+# Create a backup directory that is not empty so the next command will fail
+# but leave the data directory behind
+mkdir("$tempdir/backup")
+  or BAIL_OUT("unable to create $tempdir/backup");
+append_to_file("$tempdir/backup/dir-not-empty.txt", "Some data");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
+	'failing run with no-clean option');
+
+ok(-d "$tempdir/backup", 'backup directory was created and left behind');
+rmtree("$tempdir/backup");
+
+open my $conf, '>>', "$pgdata/postgresql.conf";
+print $conf "max_replication_slots = 10\n";
+print $conf "max_wal_senders = 10\n";
+print $conf "wal_level = replica\n";
+close $conf;
+$node->restart;
+
+# Write some files to test that they are not copied.
+foreach my $filename (
+	qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
+  )
+{
+	open my $file, '>>', "$pgdata/$filename";
+	print $file "DONOTCOPY";
+	close $file;
+}
+
+# Connect to a database to create global/pg_internal.init.  If this is removed
+# the test to ensure global/pg_internal.init is not copied will return a false
+# positive.
+$node->safe_psql('postgres', 'SELECT 1;');
+
+# Create an unlogged table to test that forks other than init are not copied.
+$node->safe_psql('postgres', 'CREATE UNLOGGED TABLE base_unlogged (id int)');
+
+my $baseUnloggedPath = $node->safe_psql('postgres',
+	q{select pg_relation_filepath('base_unlogged')});
+
+# Make sure main and init forks exist
+ok(-f "$pgdata/${baseUnloggedPath}_init", 'unlogged init fork in base');
+ok(-f "$pgdata/$baseUnloggedPath",        'unlogged main fork in base');
+
+# Create files that look like temporary relations to ensure they are ignored.
+my $postgresOid = $node->safe_psql('postgres',
+	q{select oid from pg_database where datname = 'postgres'});
+
+my @tempRelationFiles =
+  qw(t999_999 t9999_999.1 t999_9999_vm t99999_99999_vm.1);
+
+foreach my $filename (@tempRelationFiles)
+{
+	append_to_file("$pgdata/base/$postgresOid/$filename", 'TEMP_RELATION');
+}
+
+# Run base backup in parallel mode.
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backup", '-X', 'none', "-j 4" ],
+	'pg_basebackup runs');
+ok(-f "$tempdir/backup/PG_VERSION", 'backup was created');
+
+# Permissions on backup should be default
+SKIP:
+{
+	skip "unix-style permissions not supported on Windows", 1
+	  if ($windows_os);
+
+	ok(check_mode_recursive("$tempdir/backup", 0700, 0600),
+		"check backup dir permissions");
+}
+
+# Only archive_status directory should be copied in pg_wal/.
+is_deeply(
+	[ sort(slurp_dir("$tempdir/backup/pg_wal/")) ],
+	[ sort qw(. .. archive_status) ],
+	'no WAL files copied');
+
+# Contents of these directories should not be copied.
+foreach my $dirname (
+	qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
+  )
+{
+	is_deeply(
+		[ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
+		[ sort qw(. ..) ],
+		"contents of $dirname/ not copied");
+}
+
+# These files should not be copied.
+foreach my $filename (
+	qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp
+	global/pg_internal.init))
+{
+	ok(!-f "$tempdir/backup/$filename", "$filename not copied");
+}
+
+# Unlogged relation forks other than init should not be copied
+ok(-f "$tempdir/backup/${baseUnloggedPath}_init",
+	'unlogged init fork in backup');
+ok( !-f "$tempdir/backup/$baseUnloggedPath",
+	'unlogged main fork not in backup');
+
+# Temp relations should not be copied.
+foreach my $filename (@tempRelationFiles)
+{
+	ok( !-f "$tempdir/backup/base/$postgresOid/$filename",
+		"base/$postgresOid/$filename not copied");
+}
+
+# Make sure existing backup_label was ignored.
+isnt(slurp_file("$tempdir/backup/backup_label"),
+	'DONOTCOPY', 'existing backup_label not copied');
+rmtree("$tempdir/backup");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
+		"$tempdir/xlog2", "-j 4"
+	],
+	'separate xlog directory');
+ok(-f "$tempdir/backup2/PG_VERSION", 'backup was created');
+ok(-d "$tempdir/xlog2/",             'xlog directory was created');
+rmtree("$tempdir/backup2");
+rmtree("$tempdir/xlog2");
+
+$node->command_fails([ 'pg_basebackup', '-D', "$tempdir/tarbackup", '-Ft', "-j 4"],
+	'tar format');
+
+rmtree("$tempdir/tarbackup");
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T=/foo" ],
+	'-T with empty old directory fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=" ],
+	'-T with empty new directory fails');
+$node->command_fails(
+	[
+		'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4",
+		"-T/foo=/bar=/baz"
+	],
+	'-T with multiple = fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo=/bar" ],
+	'-T with old directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-T/foo=bar" ],
+	'-T with new directory not absolute fails');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_foo", '-Fp', "-j 4", "-Tfoo" ],
+	'-T with invalid format fails');
+
+# The following tests test symlinks. Windows doesn't have symlinks, so
+# skip on Windows.
+SKIP:
+{
+	skip "symlinks not supported on Windows", 18 if ($windows_os);
+
+	# Move pg_replslot out of $pgdata and create a symlink to it.
+	$node->stop;
+
+	# Set umask so test directories and files are created with group permissions
+	umask(0027);
+
+	# Enable group permissions on PGDATA
+	chmod_recursive("$pgdata", 0750, 0640);
+
+	rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
+	  or BAIL_OUT "could not move $pgdata/pg_replslot";
+	symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
+	  or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
+
+	$node->start;
+
+#	# Create a temporary directory in the system location and symlink it
+#	# to our physical temp location.  That way we can use shorter names
+#	# for the tablespace directories, which hopefully won't run afoul of
+#	# the 99 character length limit.
+	my $shorter_tempdir = TestLib::tempdir_short . "/tempdir";
+	symlink "$tempdir", $shorter_tempdir;
+
+	mkdir "$tempdir/tblspc1";
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc1 LOCATION '$shorter_tempdir/tblspc1';");
+	$node->safe_psql('postgres',
+		"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
+
+	# Create an unlogged table to test that forks other than init are not copied.
+	$node->safe_psql('postgres',
+		'CREATE UNLOGGED TABLE tblspc1_unlogged (id int) TABLESPACE tblspc1;'
+	);
+
+	my $tblspc1UnloggedPath = $node->safe_psql('postgres',
+		q{select pg_relation_filepath('tblspc1_unlogged')});
+
+	# Make sure main and init forks exist
+	ok( -f "$pgdata/${tblspc1UnloggedPath}_init",
+		'unlogged init fork in tablespace');
+	ok(-f "$pgdata/$tblspc1UnloggedPath", 'unlogged main fork in tablespace');
+
+	# Create files that look like temporary relations to ensure they are ignored
+	# in a tablespace.
+	my @tempRelationFiles = qw(t888_888 t888888_888888_vm.1);
+	my $tblSpc1Id         = basename(
+		dirname(
+			dirname(
+				$node->safe_psql(
+					'postgres', q{select pg_relation_filepath('test1')}))));
+
+	foreach my $filename (@tempRelationFiles)
+	{
+		append_to_file(
+			"$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			'TEMP_RELATION');
+	}
+
+	$node->command_fails(
+		[ 'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4" ],
+		'plain format with tablespaces fails without tablespace mapping');
+
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup1", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tblspc1=$tempdir/tbackup/tblspc1"
+		],
+		'plain format with tablespaces succeeds with tablespace mapping');
+	ok(-d "$tempdir/tbackup/tblspc1", 'tablespace was relocated');
+	opendir(my $dh, "$pgdata/pg_tblspc") or die;
+	ok( (   grep {
+				-l "$tempdir/backup1/pg_tblspc/$_"
+				  and readlink "$tempdir/backup1/pg_tblspc/$_" eq
+				  "$tempdir/tbackup/tblspc1"
+			} readdir($dh)),
+		"tablespace symlink was updated");
+	closedir $dh;
+
+	# Group access should be enabled on all backup files
+	ok(check_mode_recursive("$tempdir/backup1", 0750, 0640),
+		"check backup dir permissions");
+
+	# Unlogged relation forks other than init should not be copied
+	my ($tblspc1UnloggedBackupPath) =
+	  $tblspc1UnloggedPath =~ /[^\/]*\/[^\/]*\/[^\/]*$/g;
+
+	ok(-f "$tempdir/tbackup/tblspc1/${tblspc1UnloggedBackupPath}_init",
+		'unlogged init fork in tablespace backup');
+	ok(!-f "$tempdir/tbackup/tblspc1/$tblspc1UnloggedBackupPath",
+		'unlogged main fork not in tablespace backup');
+
+	# Temp relations should not be copied.
+	foreach my $filename (@tempRelationFiles)
+	{
+		ok( !-f "$tempdir/tbackup/tblspc1/$tblSpc1Id/$postgresOid/$filename",
+			"[tblspc1]/$postgresOid/$filename not copied");
+
+		# Also remove temp relation files or tablespace drop will fail.
+		my $filepath =
+		  "$shorter_tempdir/tblspc1/$tblSpc1Id/$postgresOid/$filename";
+
+		unlink($filepath)
+		  or BAIL_OUT("unable to unlink $filepath");
+	}
+
+	ok( -d "$tempdir/backup1/pg_replslot",
+		'pg_replslot symlink copied as directory');
+	rmtree("$tempdir/backup1");
+
+	mkdir "$tempdir/tbl=spc2";
+	$node->safe_psql('postgres', "DROP TABLE test1;");
+	$node->safe_psql('postgres', "DROP TABLE tblspc1_unlogged;");
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc1;");
+	$node->safe_psql('postgres',
+		"CREATE TABLESPACE tblspc2 LOCATION '$shorter_tempdir/tbl=spc2';");
+	$node->command_ok(
+		[
+			'pg_basebackup', '-D', "$tempdir/backup3", '-Fp', "-j 4",
+			"-T$shorter_tempdir/tbl\\=spc2=$tempdir/tbackup/tbl\\=spc2"
+		],
+		'mapping tablespace with = sign in path');
+	ok(-d "$tempdir/tbackup/tbl=spc2",
+		'tablespace with = sign was relocated');
+	$node->safe_psql('postgres', "DROP TABLESPACE tblspc2;");
+	rmtree("$tempdir/backup3");
+}
+
+$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' , '-j 4'],
+	'pg_basebackup -R runs');
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf exists');
+ok(-f "$tempdir/backupR/standby.signal",       'standby.signal was created');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
+rmtree("$tempdir/backupR");
+
+my $port = $node->port;
+like(
+	$recovery_conf,
+	qr/^primary_conninfo = '.*port=$port.*'\n/m,
+	'postgresql.auto.conf sets primary_conninfo');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxd" , "-j 4"],
+	'pg_basebackup runs in default xlog mode');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxd");
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxf", '-X', 'fetch' , "-j 4"],
+	'pg_basebackup -X fetch runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxf/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxf");
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs", '-X', 'stream' , "-j 4"],
+	'pg_basebackup -X stream runs');
+ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxs/pg_wal")),
+	'WAL files copied');
+rmtree("$tempdir/backupxs");
+
+$node->command_ok(
+	[
+		'pg_basebackup',         '-D',
+		"$tempdir/backupnoslot", '-X',
+		'stream',                '--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup -X stream runs with --no-slot');
+rmtree("$tempdir/backupnoslot");
+
+$node->command_fails(
+	[
+		'pg_basebackup',             '-D',
+		"$tempdir/backupxs_sl_fail", '-X',
+		'stream',                    '-S',
+		'slot0',
+		'-j 4'
+	],
+	'pg_basebackup fails with nonexistent replication slot');
+#
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C' , '-j 4'],
+	'pg_basebackup -C fails without slot name');
+
+$node->command_fails(
+	[
+		'pg_basebackup',          '-D',
+		"$tempdir/backupxs_slot", '-C',
+		'-S',                     'slot0',
+		'--no-slot',
+		'-j 4'
+	],
+	'pg_basebackup fails with -C -S --no-slot');
+
+$node->command_ok(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup -C runs');
+rmtree("$tempdir/backupxs_slot");
+
+is( $node->safe_psql(
+		'postgres',
+		q{SELECT slot_name FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'slot0',
+	'replication slot was created');
+isnt(
+	$node->safe_psql(
+		'postgres',
+		q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot0'}
+	),
+	'',
+	'restart LSN of new slot is not null');
+
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/backupxs_slot1", '-C', '-S', 'slot0', '-j 4'],
+	'pg_basebackup fails with -C -S and a previously existing slot');
+
+$node->safe_psql('postgres',
+	q{SELECT * FROM pg_create_physical_replication_slot('slot1')});
+my $lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+is($lsn, '', 'restart LSN of new slot is null');
+$node->command_fails(
+	[ 'pg_basebackup', '-D', "$tempdir/fail", '-S', 'slot1', '-X', 'none', '-j 4'],
+	'pg_basebackup with replication slot fails without WAL streaming');
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl", '-X',
+		'stream',        '-S', 'slot1', '-j 4'
+	],
+	'pg_basebackup -X stream with replication slot runs');
+$lsn = $node->safe_psql('postgres',
+	q{SELECT restart_lsn FROM pg_replication_slots WHERE slot_name = 'slot1'}
+);
+like($lsn, qr!^0/[0-9A-Z]{7,8}$!, 'restart LSN of slot has advanced');
+rmtree("$tempdir/backupxs_sl");
+
+$node->command_ok(
+	[
+		'pg_basebackup', '-D', "$tempdir/backupxs_sl_R", '-X',
+		'stream',        '-S', 'slot1',                  '-R',
+		'-j 4'
+	],
+	'pg_basebackup with replication slot and -R runs');
+like(
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
+	qr/^primary_slot_name = 'slot1'\n/m,
+	'recovery conf file sets primary_slot_name');
+
+my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
+is($checksum, 'on', 'checksums are enabled');
+rmtree("$tempdir/backupxs_sl_R");
+
+# create tables to corrupt and get their relfilenodes
+my $file_corrupt1 = $node->safe_psql('postgres',
+	q{SELECT a INTO corrupt1 FROM generate_series(1,10000) AS a; ALTER TABLE corrupt1 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt1')}
+);
+my $file_corrupt2 = $node->safe_psql('postgres',
+	q{SELECT b INTO corrupt2 FROM generate_series(1,2) AS b; ALTER TABLE corrupt2 SET (autovacuum_enabled=false); SELECT pg_relation_filepath('corrupt2')}
+);
+
+# set page header and block sizes
+my $pageheader_size = 24;
+my $block_size = $node->safe_psql('postgres', 'SHOW block_size;');
+
+# induce corruption
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+my $file;
+open $file, '+<', "$pgdata/$file_corrupt1";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*checksum verification failed/s],
+	'pg_basebackup reports checksum mismatch');
+rmtree("$tempdir/backup_corrupt");
+
+# induce further corruption in 5 more blocks
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt1";
+for my $i (1 .. 5)
+{
+	my $offset = $pageheader_size + $i * $block_size;
+	seek($file, $offset, 0);
+	syswrite($file, "\0\0\0\0\0\0\0\0\0");
+}
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+$node->command_checks_all(
+	[ 'pg_basebackup', '-D', "$tempdir/backup_corrupt2", '-j 4'],
+	1,
+	[qr{^$}],
+	[qr/^WARNING.*further.*failures.*will.not.be.reported/s],
+	'pg_basebackup does not report more than 5 checksum mismatches');
+rmtree("$tempdir/backup_corrupt2");
+
+# induce corruption in a second file
+system_or_bail 'pg_ctl', '-D', $pgdata, 'stop';
+open $file, '+<', "$pgdata/$file_corrupt2";
+seek($file, $pageheader_size, 0);
+syswrite($file, "\0\0\0\0\0\0\0\0\0");
+close $file;
+system_or_bail 'pg_ctl', '-D', $pgdata, 'start';
+
+# do not verify checksums, should return ok
+$node->command_ok(
+	[
+		'pg_basebackup',            '-D',
+		"$tempdir/backup_corrupt4", '--no-verify-checksums',
+		'-j 4'
+	],
+	'pg_basebackup with -k does not report checksum mismatch');
+rmtree("$tempdir/backup_corrupt4");
+
+$node->safe_psql('postgres', "DROP TABLE corrupt1;");
+$node->safe_psql('postgres', "DROP TABLE corrupt2;");
-- 
2.21.1 (Apple Git-122.3)

0006-parallel-backup-documentation_v9.patchapplication/octet-stream; name=0006-parallel-backup-documentation_v9.patchDownload
From 9d41ac12788e5bc8b674cc24784d2cfac75d7d14 Mon Sep 17 00:00:00 2001
From: Asif Rehman <asif.rehman@highgo.ca>
Date: Fri, 14 Feb 2020 17:02:51 +0500
Subject: [PATCH 6/6] parallel backup - documentation

---
 doc/src/sgml/protocol.sgml          | 366 ++++++++++++++++++++++++++++
 doc/src/sgml/ref/pg_basebackup.sgml |  20 ++
 2 files changed, 386 insertions(+)

diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index f139ba02312..8c420a08dc8 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -2700,6 +2700,372 @@ The commands accepted in replication mode are:
      </para>
     </listitem>
   </varlistentry>
+  
+  <varlistentry>
+    <term><literal>START_BACKUP</literal>
+        [ <literal>LABEL</literal> <replaceable>'label'</replaceable> ]
+        [ <literal>FAST</literal> ]
+     <indexterm><primary>START_BACKUP</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instructs the server to prepare for performing on-line backup. The following
+      options are accepted:
+      <variablelist>
+       <varlistentry>
+        <term><literal>LABEL</literal> <replaceable>'label'</replaceable></term>
+        <listitem>
+         <para>
+          Sets the label of the backup. If none is specified, a backup label
+          of <literal>start backup</literal> will be used. The quoting rules
+          for the label are the same as a standard SQL string with
+          <xref linkend="guc-standard-conforming-strings"/> turned on.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>FAST</literal></term>
+        <listitem>
+         <para>
+          Request a fast checkpoint.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a single result set. The
+      first column contains the start position given in XLogRecPtr format, and
+      the second column contains the corresponding timeline ID.
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>STOP_BACKUP</literal>
+        [ <literal>NOWAIT</literal> ]
+     <indexterm><primary>STOP_BACKUP</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instructs the server to finish performing on-line backup.
+      <variablelist>
+       <varlistentry>
+        <term><literal>NOWAIT</literal></term>
+        <listitem>
+         <para>
+          By default, the backup will wait until the last required WAL
+          segment has been archived, or emit a warning if log archiving is
+          not enabled. Specifying <literal>NOWAIT</literal> disables both
+          the waiting and the warning, leaving the client responsible for
+          ensuring the required log is available.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a single result set. The
+      first column contains the start position given in XLogRecPtr format, the
+      second column contains the corresponding timeline ID and the third column
+      contains the contents of the <filename>backup_label</filename> file.
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>LIST_TABLESPACES</literal>
+        [ <literal>PROGRESS</literal> ]
+      <indexterm><primary>LIST_TABLESPACES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instruct the server to return a list of tablespaces available in data
+      directory.
+      <variablelist>
+       <varlistentry>
+        <term><literal>PROGRESS</literal></term>
+        <listitem>
+         <para>
+          Request information required to generate a progress report. This will
+          send back an approximate size in the header of each tablespace, which
+          can be used to calculate how far along the stream is done. This is
+          calculated by enumerating all the file sizes once before the transfer
+          is even started, and might as such have a negative impact on the
+          performance.  In particular, it might take longer before the first data
+          is streamed. Since the database files can change during the backup,
+          the size is only approximate and might both grow and shrink between
+          the time of approximation and the sending of the actual files.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send one result set.
+      The result set will have one row for each tablespace. The fields in this
+      row are:
+      <variablelist>
+       <varlistentry>
+        <term><literal>spcoid</literal> (<type>oid</type>)</term>
+        <listitem>
+         <para>
+          The OID of the tablespace, or null if it's the base directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>spclocation</literal> (<type>text</type>)</term>
+        <listitem>
+         <para>
+          The full path of the tablespace directory, or null if it's the base
+          directory.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+        <para>
+         The approximate size of the tablespace, in kilobytes (1024 bytes),
+         if progress report has been requested; otherwise it's null.
+        </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>LIST_FILES</literal>
+        [ <literal>TABLESPACE</literal> ]
+     <indexterm><primary>LIST_FILES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      This command instructs the server to return a list of files available
+      in the given tablespace.
+      <variablelist>
+       <varlistentry>
+        <term><literal>TABLESPACE</literal></term>
+        <listitem>
+         <para>
+          name of the tablespace. If its empty or not provided then 'base' tablespace
+          is assumed.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a result set. The fields
+      in this result set are:
+      <variablelist>
+       <varlistentry>
+        <term><literal>path</literal> (<type>text</type>)</term>
+        <listitem>
+         <para>
+          The path and name of the file. In case of tablespace, it is an absolute
+          path on the database server, however, in case of <filename>base</filename>
+          tablespace, it is relative to $PGDATA.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>type</literal> (<type>char</type>)</term>
+        <listitem>
+         <para>
+          A single character, identifying the type of file.
+          <itemizedlist spacing="compact" mark="bullet">
+           <listitem>
+            <para>
+             <literal>'f'</literal> - Regular file. Can be any relation or
+             non-relation file in $PGDATA.
+            </para>
+           </listitem>
+           <listitem>
+            <para>
+             <literal>'d'</literal> - Directory.
+            </para>
+           </listitem>
+           <listitem>
+            <para>
+             <literal>'l'</literal> - Symbolic link.
+            </para>
+           </listitem>
+          </itemizedlist>
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>size</literal> (<type>int8</type>)</term>
+        <listitem>
+         <para>
+          The approximate size of the file, in kilobytes (1024 bytes). It's null
+          if type is 'd' or 'l'.
+         </para>
+        </listitem>
+       </varlistentry>
+       <varlistentry>
+        <term><literal>mtime</literal> (<type>Int64</type>)</term>
+        <listitem>
+         <para>
+          The file or directory last modification time, as seconds since the Epoch.
+         </para>
+        </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      The list will contain all files in tablespace directory, regardless of whether
+      they are PostgreSQL files or other files added to the same directory. The only
+      excluded files are:
+      <itemizedlist spacing="compact" mark="bullet">
+       <listitem>
+        <para>
+         <filename>postmaster.pid</filename>
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>postmaster.opts</filename>
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>pg_internal.init</filename> (found in multiple directories)
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         Various temporary files and directories created during the operation
+         of the PostgreSQL server, such as any file or directory beginning
+         with <filename>pgsql_tmp</filename> and temporary relations.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         Unlogged relations, except for the init fork which is required to
+         recreate the (empty) unlogged relation on recovery.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>pg_wal</filename>, including subdirectories. If the backup is run
+         with WAL files included, a synthesized version of <filename>pg_wal</filename>
+         will be included, but it will only contain the files necessary for the backup
+         to work, not the rest of the contents.
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         <filename>pg_dynshmem</filename>, <filename>pg_notify</filename>,
+         <filename>pg_replslot</filename>, <filename>pg_serial</filename>,
+         <filename>pg_snapshots</filename>, <filename>pg_stat_tmp</filename>, and
+         <filename>pg_subtrans</filename> are copied as empty directories (even if
+         they are symbolic links).
+        </para>
+       </listitem>
+       <listitem>
+        <para>
+         Files other than regular files and directories, such as symbolic
+         links (other than for the directories listed above) and special
+         device files, are skipped.  (Symbolic links
+         in <filename>pg_tblspc</filename> are maintained.)
+        </para>
+       </listitem>
+      </itemizedlist>
+     </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>LIST_WAL_FILES</literal>
+        <literal>START_WAL_LOCATION</literal> <replaceable class="parameter">X/X</replaceable>
+        <literal>END_WAL_LOCATION</literal> <replaceable class="parameter">X/X</replaceable>
+      <indexterm><primary>LIST_WAL_FILES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instruct the server to return a list of WAL files available in pg_wal directory.
+      The following options are accepted:
+      <variablelist>
+       <varlistentry>
+         <term><literal>START_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The starting WAL position when START BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><literal>END_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The ending WAL position when STOP BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+     <para>
+      In response to this command, server will send out a result and each row will
+      consist of a WAL file entry. The result set will have the same fields as
+      <literal>LIST_FILES</literal> command.
+      </para>
+    </listitem>
+  </varlistentry>
+
+  <varlistentry>
+    <term><literal>SEND_FILES ( <replaceable class="parameter">'FILE'</replaceable> [, ...] )</literal>
+        [ <literal>START_WAL_LOCATION</literal> <replaceable class="parameter">X/X</replaceable> ]
+        [ <literal>NOVERIFY_CHECKSUMS</literal> ]
+        <indexterm><primary>SEND_FILES</primary></indexterm>
+    </term>
+    <listitem>
+     <para>
+      Instructs the server to send the contents of the requested FILE(s).
+     </para>
+     <para>
+      A clause of the form <literal>SEND_FILES ( 'FILE', 'FILE', ... ) [OPTIONS]</literal>
+      is accepted where one or more FILE(s) can be requested.
+     </para>
+     <para>
+      In response to this command, one or more CopyResponse results will be sent,
+      one for each FILE requested. The data in the CopyResponse results will be
+      a tar format (following the “ustar interchange format” specified in the
+      POSIX 1003.1-2008 standard) dump of the tablespace contents, except that
+      the two trailing blocks of zeroes specified in the standard are omitted.
+     </para>
+     <para>
+      The following options are accepted:
+      <variablelist>
+       <varlistentry>
+         <term><literal>START_WAL_LOCATION</literal></term>
+         <listitem>
+          <para>
+           The starting WAL position when START BACKUP command was issued,
+           returned in the form of XLogRecPtr format.
+          </para>
+         </listitem>
+       </varlistentry>
+       <varlistentry>
+         <term><literal>NOVERIFY_CHECKSUMS</literal></term>
+         <listitem>
+          <para>
+           By default, checksums are verified during a base backup if they are
+           enabled. Specifying <literal>NOVERIFY_CHECKSUMS</literal> disables
+           this verification.
+          </para>
+         </listitem>
+       </varlistentry>
+      </variablelist>
+     </para>
+    </listitem>
+  </varlistentry>
 </variablelist>
 
 </para>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index 29bf2f9b979..14b5fb1f5d8 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -552,6 +552,26 @@ PostgreSQL documentation
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry>
+      <term><option>-j <replaceable class="parameter">n</replaceable></option></term>
+      <term><option>--jobs=<replaceable class="parameter">n</replaceable></option></term>
+      <listitem>
+       <para>
+        Create <replaceable class="parameter">n</replaceable> threads to copy
+        backup files from the database server. <application>pg_basebackup</application>
+        will open at least <replaceable class="parameter">n</replaceable> + 1
+        connections to the database. An additional connection is made if WAL
+        streaming is enabled. Therefore, the server must be configured with
+        <xref linkend="guc-max-wal-senders"/> set high enough to accommodate all
+        connections.
+       </para>
+       <para>
+        parallel mode only works with plain format.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </para>
 
-- 
2.21.1 (Apple Git-122.3)

#48Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Asif Rehman (#47)
Re: WIP/PoC for parallel backup

Thanks for the patches.

I have verified reported issues with new patches, issues are fixed now.

I got another observation where If a new slot name given without -C option,
it leads to server crash error.

[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 4 -D /tmp/bkp --slot
test_bkp_slot
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test_bkp_slot" does not exist
pg_basebackup: error: could not list backup files: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing data directory "/tmp/bkp"

Thanks & Regards,
Rajkumar Raghuwanshi

On Fri, Mar 13, 2020 at 9:51 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Show quoted text

On Wed, Mar 11, 2020 at 2:38 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif

I have started testing this feature. I have applied v6 patch on commit
a069218163704c44a8996e7e98e765c56e2b9c8e (30 Jan).
I got few observations, please take a look.

*--if backup failed, backup directory is not getting removed.*
[edb@localhost bin]$ ./pg_basebackup -p 5432 --jobs=9 -D
/tmp/test_bkp/bkp6
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
[edb@localhost bin]$ ./pg_basebackup -p 5432 --jobs=8 -D
/tmp/test_bkp/bkp6
pg_basebackup: error: directory "/tmp/test_bkp/bkp6" exists but is not
empty

*--giving large number of jobs leading segmentation fault.*
./pg_basebackup -p 5432 --jobs=1000 -D /tmp/t3
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
.
.
.
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: error: could not connect to server: could not fork new
process for connection: Resource temporarily unavailable

could not fork new process for connection: Resource temporarily
unavailable
pg_basebackup: error: failed to create thread: Resource temporarily
unavailable
Segmentation fault (core dumped)

--stack-trace
gdb -q -c core.11824 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 --jobs=1000 -D
/tmp/test_bkp/bkp10'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=140503120623360, thread_return=0x0) at
pthread_join.c:46
46 if (INVALID_NOT_TERMINATED_TD_P (pd))
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 pthread_join (threadid=140503120623360, thread_return=0x0) at
pthread_join.c:46
#1 0x0000000000408e21 in cleanup_workers () at pg_basebackup.c:2840
#2 0x0000000000403846 in disconnect_atexit () at pg_basebackup.c:316
#3 0x0000003921235a02 in __run_exit_handlers (status=1) at exit.c:78
#4 exit (status=1) at exit.c:100
#5 0x0000000000408aa6 in create_parallel_workers (backupinfo=0x1a4b8c0)
at pg_basebackup.c:2713
#6 0x0000000000407946 in BaseBackup () at pg_basebackup.c:2127
#7 0x000000000040895c in main (argc=6, argv=0x7ffd566f4718) at
pg_basebackup.c:2668

*--with tablespace is in the same directory as data, parallel_backup
crashed*
[edb@localhost bin]$ ./initdb -D /tmp/data
[edb@localhost bin]$ ./pg_ctl -D /tmp/data -l /tmp/logfile start
[edb@localhost bin]$ mkdir /tmp/ts
[edb@localhost bin]$ ./psql postgres
psql (13devel)
Type "help" for help.

postgres=# create tablespace ts location '/tmp/ts';
CREATE TABLESPACE
postgres=# create table tx (a int) tablespace ts;
CREATE TABLE
postgres=# \q
[edb@localhost bin]$ ./pg_basebackup -j 2 -D /tmp/tts -T /tmp/ts=/tmp/ts1
Segmentation fault (core dumped)

--stack-trace
[edb@localhost bin]$ gdb -q -c core.15778 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -j 2 -D /tmp/tts -T
/tmp/ts=/tmp/ts1'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000000000409442 in get_backup_filelist (conn=0x140cb20,
backupInfo=0x14210a0) at pg_basebackup.c:3000
3000 backupInfo->curr->next = file;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x0000000000409442 in get_backup_filelist (conn=0x140cb20,
backupInfo=0x14210a0) at pg_basebackup.c:3000
#1 0x0000000000408b56 in parallel_backup_run (backupinfo=0x14210a0) at
pg_basebackup.c:2739
#2 0x0000000000407955 in BaseBackup () at pg_basebackup.c:2128
#3 0x000000000040895c in main (argc=7, argv=0x7ffca2910c58) at
pg_basebackup.c:2668
(gdb)

Thanks Rajkumar. I have fixed the above issues and have rebased the patch
to the latest master (b7f64c64).
(V9 of the patches are attached).

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#49Asif Rehman
asifr.rehman@gmail.com
In reply to: Rajkumar Raghuwanshi (#48)
Re: WIP/PoC for parallel backup

On Mon, Mar 16, 2020 at 11:08 AM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Thanks for the patches.

I have verified reported issues with new patches, issues are fixed now.

I got another observation where If a new slot name given without -C
option, it leads to server crash error.

[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 4 -D /tmp/bkp --slot
test_bkp_slot
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test_bkp_slot" does not exist
pg_basebackup: error: could not list backup files: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing data directory "/tmp/bkp"

It seems to be an expected behavior. The START_BACKUP command has been
executed, and
pg_basebackup tries to start a WAL streaming process with a non-existent
slot, which results in
an error. So the backup is aborted while terminating all other processes.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#50Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Asif Rehman (#49)
Re: WIP/PoC for parallel backup

On Mon, Mar 16, 2020 at 11:52 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Mon, Mar 16, 2020 at 11:08 AM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Thanks for the patches.

I have verified reported issues with new patches, issues are fixed now.

I got another observation where If a new slot name given without -C
option, it leads to server crash error.

[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 4 -D /tmp/bkp --slot
test_bkp_slot
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test_bkp_slot" does not exist
pg_basebackup: error: could not list backup files: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing data directory "/tmp/bkp"

It seems to be an expected behavior. The START_BACKUP command has been
executed, and
pg_basebackup tries to start a WAL streaming process with a non-existent
slot, which results in
an error. So the backup is aborted while terminating all other processes.

I think error message can be improved. current error message looks like
database server is crashed.

on PG same is existing with exit 1.
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp --slot
test_bkp_slot
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test_bkp_slot" does not exist
pg_basebackup: error: child process exited with exit code 1
pg_basebackup: removing data directory "/tmp/bkp"

Show quoted text

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#51Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Asif Rehman (#47)
Re: WIP/PoC for parallel backup

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the patch
to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out
pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

2. With parallel jobs, maxrate is now not supported. Since we are now asking
data in multiple threads throttling seems important here. Can you please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested, let
rename
SEND_FILES to SEND_FILE instead.

4. Does this work on Windows? I mean does pthread_create() work on Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

5. Typos:
tablspace => tablespace
safly => safely

6. parallel_backup_run() needs some comments explaining the states it goes
through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Thanks
--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

Phone: +91 20 66449694

Website: www.enterprisedb.com
EnterpriseDB Blog: http://blogs.enterprisedb.com/
Follow us on Twitter: http://www.twitter.com/enterprisedb

This e-mail message (and any attachment) is intended for the use of the
individual or entity to whom it is addressed. This message contains
information from EnterpriseDB Corporation that may be privileged,
confidential, or exempt from disclosure under applicable law. If you are
not the intended recipient or authorized to receive this for the intended
recipient, any use, dissemination, distribution, retention, archiving, or
copying of this communication is strictly prohibited. If you have received
this e-mail in error, please notify the sender immediately by reply e-mail
and delete this message.

#52Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Jeevan Chalke (#51)
Re: WIP/PoC for parallel backup

Hi Asif,

On testing further, I found when taking backup with -R, pg_basebackup
crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test values
('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp -R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp
-R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Show quoted text

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the patch
to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out
pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

2. With parallel jobs, maxrate is now not supported. Since we are now
asking
data in multiple threads throttling seems important here. Can you please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested, let
rename
SEND_FILES to SEND_FILE instead.

4. Does this work on Windows? I mean does pthread_create() work on Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

5. Typos:
tablspace => tablespace
safly => safely

6. parallel_backup_run() needs some comments explaining the states it goes
through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Thanks
--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

Phone: +91 20 66449694

Website: www.enterprisedb.com
EnterpriseDB Blog: http://blogs.enterprisedb.com/
Follow us on Twitter: http://www.twitter.com/enterprisedb

This e-mail message (and any attachment) is intended for the use of the
individual or entity to whom it is addressed. This message contains
information from EnterpriseDB Corporation that may be privileged,
confidential, or exempt from disclosure under applicable law. If you are
not the intended recipient or authorized to receive this for the intended
recipient, any use, dissemination, distribution, retention, archiving, or
copying of this communication is strictly prohibited. If you have received
this e-mail in error, please notify the sender immediately by reply e-mail
and delete this message.

#53Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Rajkumar Raghuwanshi (#52)
Re: WIP/PoC for parallel backup

Hi Asif,

In another scenarios, bkp data is corrupted for tablespace. again this is
not reproducible everytime,
but If I am running the same set of commands I am getting the same error.

[edb@localhost bin]$ ./pg_ctl -D data -l logfile start
waiting for server to start.... done
server started
[edb@localhost bin]$
[edb@localhost bin]$ mkdir /tmp/tblsp
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace tblsp
location '/tmp/tblsp';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create database testdb
tablespace tblsp;"
CREATE DATABASE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "create table testtbl (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "insert into testtbl values
('parallel_backup with tablespace');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp -T
/tmp/tblsp=/tmp/tblsp_bkp --jobs 2
[edb@localhost bin]$ ./pg_ctl -D /tmp/bkp -l /tmp/bkp_logs -o "-p 5555"
start
waiting for server to start.... done
server started
[edb@localhost bin]$ ./psql postgres -p 5555 -c "select * from
pg_tablespace where spcname like 'tblsp%' or spcname = 'pg_default'";
oid | spcname | spcowner | spcacl | spcoptions
-------+------------+----------+--------+------------
1663 | pg_default | 10 | |
16384 | tblsp | 10 | |
(2 rows)

[edb@localhost bin]$ ./psql testdb -p 5555 -c "select * from testtbl";
psql: error: could not connect to server: FATAL:
"pg_tblspc/16384/PG_13_202003051/16385" is not a valid data directory
DETAIL: File "pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION" is missing.
[edb@localhost bin]$
[edb@localhost bin]$ ls
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
[edb@localhost bin]$ ls
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
ls: cannot access
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION: No such file or
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 6:19 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Show quoted text

Hi Asif,

On testing further, I found when taking backup with -R, pg_basebackup
crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test values
('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp -R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp
-R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the
patch to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out
pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

2. With parallel jobs, maxrate is now not supported. Since we are now
asking
data in multiple threads throttling seems important here. Can you please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested, let
rename
SEND_FILES to SEND_FILE instead.

4. Does this work on Windows? I mean does pthread_create() work on
Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

5. Typos:
tablspace => tablespace
safly => safely

6. parallel_backup_run() needs some comments explaining the states it goes
through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Thanks
--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

Phone: +91 20 66449694

Website: www.enterprisedb.com
EnterpriseDB Blog: http://blogs.enterprisedb.com/
Follow us on Twitter: http://www.twitter.com/enterprisedb

This e-mail message (and any attachment) is intended for the use of the
individual or entity to whom it is addressed. This message contains
information from EnterpriseDB Corporation that may be privileged,
confidential, or exempt from disclosure under applicable law. If you are
not the intended recipient or authorized to receive this for the intended
recipient, any use, dissemination, distribution, retention, archiving, or
copying of this communication is strictly prohibited. If you have received
this e-mail in error, please notify the sender immediately by reply e-mail
and delete this message.

#54Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Rajkumar Raghuwanshi (#53)
Re: WIP/PoC for parallel backup

Hi Asif,

While testing further I observed parallel backup is not able to take backup
of standby server.

mkdir /tmp/archive_dir
echo "archive_mode='on'">> data/postgresql.conf
echo "archive_command='cp %p /tmp/archive_dir/%f'">> data/postgresql.conf

./pg_ctl -D data -l logs start
./pg_basebackup -p 5432 -Fp -R -D /tmp/slave

echo "primary_conninfo='host=127.0.0.1 port=5432 user=edb'">>
/tmp/slave/postgresql.conf
echo "restore_command='cp /tmp/archive_dir/%f %p'">>
/tmp/slave/postgresql.conf
echo "promote_trigger_file='/tmp/failover.log'">> /tmp/slave/postgresql.conf

./pg_ctl -D /tmp/slave -l /tmp/slave_logs -o "-p 5433" start -c

[edb@localhost bin]$ ./psql postgres -p 5432 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
f
(1 row)

[edb@localhost bin]$ ./psql postgres -p 5433 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
t
(1 row)

*[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs
6pg_basebackup: error: could not list backup files: ERROR: the standby was
promoted during online backupHINT: This means that the backup being taken
is corrupt and should not be used. Try taking another online
backup.pg_basebackup: removing data directory "/tmp/bkp_s"*

#same is working fine without parallel backup
[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs 1
[edb@localhost bin]$ ls /tmp/bkp_s/PG_VERSION
/tmp/bkp_s/PG_VERSION

Thanks & Regards,
Rajkumar Raghuwanshi

On Thu, Mar 19, 2020 at 4:11 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Show quoted text

Hi Asif,

In another scenarios, bkp data is corrupted for tablespace. again this is
not reproducible everytime,
but If I am running the same set of commands I am getting the same error.

[edb@localhost bin]$ ./pg_ctl -D data -l logfile start
waiting for server to start.... done
server started
[edb@localhost bin]$
[edb@localhost bin]$ mkdir /tmp/tblsp
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace tblsp
location '/tmp/tblsp';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create database testdb
tablespace tblsp;"
CREATE DATABASE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "create table testtbl (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "insert into testtbl values
('parallel_backup with tablespace');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp -T
/tmp/tblsp=/tmp/tblsp_bkp --jobs 2
[edb@localhost bin]$ ./pg_ctl -D /tmp/bkp -l /tmp/bkp_logs -o "-p 5555"
start
waiting for server to start.... done
server started
[edb@localhost bin]$ ./psql postgres -p 5555 -c "select * from
pg_tablespace where spcname like 'tblsp%' or spcname = 'pg_default'";
oid | spcname | spcowner | spcacl | spcoptions
-------+------------+----------+--------+------------
1663 | pg_default | 10 | |
16384 | tblsp | 10 | |
(2 rows)

[edb@localhost bin]$ ./psql testdb -p 5555 -c "select * from testtbl";
psql: error: could not connect to server: FATAL:
"pg_tblspc/16384/PG_13_202003051/16385" is not a valid data directory
DETAIL: File "pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION" is
missing.
[edb@localhost bin]$
[edb@localhost bin]$ ls
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
[edb@localhost bin]$ ls
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
ls: cannot access
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION: No such file or
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 6:19 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

On testing further, I found when taking backup with -R, pg_basebackup
crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test values
('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp -R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp
-R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at
pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the
patch to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out
pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

2. With parallel jobs, maxrate is now not supported. Since we are now
asking
data in multiple threads throttling seems important here. Can you please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested, let
rename
SEND_FILES to SEND_FILE instead.

4. Does this work on Windows? I mean does pthread_create() work on
Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

5. Typos:
tablspace => tablespace
safly => safely

6. parallel_backup_run() needs some comments explaining the states it
goes
through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from server
*/
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Thanks
--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

Phone: +91 20 66449694

Website: www.enterprisedb.com
EnterpriseDB Blog: http://blogs.enterprisedb.com/
Follow us on Twitter: http://www.twitter.com/enterprisedb

This e-mail message (and any attachment) is intended for the use of the
individual or entity to whom it is addressed. This message contains
information from EnterpriseDB Corporation that may be privileged,
confidential, or exempt from disclosure under applicable law. If you are
not the intended recipient or authorized to receive this for the intended
recipient, any use, dissemination, distribution, retention, archiving, or
copying of this communication is strictly prohibited. If you have received
this e-mail in error, please notify the sender immediately by reply e-mail
and delete this message.

#55Asif Rehman
asifr.rehman@gmail.com
In reply to: Rajkumar Raghuwanshi (#54)
1 attachment(s)
Re: WIP/PoC for parallel backup

On Wed, Mar 25, 2020 at 12:22 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

While testing further I observed parallel backup is not able to take
backup of standby server.

mkdir /tmp/archive_dir
echo "archive_mode='on'">> data/postgresql.conf
echo "archive_command='cp %p /tmp/archive_dir/%f'">> data/postgresql.conf

./pg_ctl -D data -l logs start
./pg_basebackup -p 5432 -Fp -R -D /tmp/slave

echo "primary_conninfo='host=127.0.0.1 port=5432 user=edb'">>
/tmp/slave/postgresql.conf
echo "restore_command='cp /tmp/archive_dir/%f %p'">>
/tmp/slave/postgresql.conf
echo "promote_trigger_file='/tmp/failover.log'">>
/tmp/slave/postgresql.conf

./pg_ctl -D /tmp/slave -l /tmp/slave_logs -o "-p 5433" start -c

[edb@localhost bin]$ ./psql postgres -p 5432 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
f
(1 row)

[edb@localhost bin]$ ./psql postgres -p 5433 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
t
(1 row)

*[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs
6pg_basebackup: error: could not list backup files: ERROR: the standby was
promoted during online backupHINT: This means that the backup being taken
is corrupt and should not be used. Try taking another online
backup.pg_basebackup: removing data directory "/tmp/bkp_s"*

#same is working fine without parallel backup
[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs 1
[edb@localhost bin]$ ls /tmp/bkp_s/PG_VERSION
/tmp/bkp_s/PG_VERSION

Thanks & Regards,
Rajkumar Raghuwanshi

On Thu, Mar 19, 2020 at 4:11 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

In another scenarios, bkp data is corrupted for tablespace. again this is
not reproducible everytime,
but If I am running the same set of commands I am getting the same error.

[edb@localhost bin]$ ./pg_ctl -D data -l logfile start
waiting for server to start.... done
server started
[edb@localhost bin]$
[edb@localhost bin]$ mkdir /tmp/tblsp
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace tblsp
location '/tmp/tblsp';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create database testdb
tablespace tblsp;"
CREATE DATABASE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "create table testtbl (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "insert into testtbl
values ('parallel_backup with tablespace');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp -T
/tmp/tblsp=/tmp/tblsp_bkp --jobs 2
[edb@localhost bin]$ ./pg_ctl -D /tmp/bkp -l /tmp/bkp_logs -o "-p 5555"
start
waiting for server to start.... done
server started
[edb@localhost bin]$ ./psql postgres -p 5555 -c "select * from
pg_tablespace where spcname like 'tblsp%' or spcname = 'pg_default'";
oid | spcname | spcowner | spcacl | spcoptions
-------+------------+----------+--------+------------
1663 | pg_default | 10 | |
16384 | tblsp | 10 | |
(2 rows)

[edb@localhost bin]$ ./psql testdb -p 5555 -c "select * from testtbl";
psql: error: could not connect to server: FATAL:
"pg_tblspc/16384/PG_13_202003051/16385" is not a valid data directory
DETAIL: File "pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION" is
missing.
[edb@localhost bin]$
[edb@localhost bin]$ ls
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
[edb@localhost bin]$ ls
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
ls: cannot access
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION: No such file or
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 6:19 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

On testing further, I found when taking backup with -R, pg_basebackup
crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test
values ('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp
-R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp
-R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at
pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the
patch to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends out
pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

Fixed.

2. With parallel jobs, maxrate is now not supported. Since we are now
asking
data in multiple threads throttling seems important here. Can you please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested, let
rename
SEND_FILES to SEND_FILE instead.

Yes, we are fetching a single file. However, SEND_FILES is still capable of
fetching multiple files in one
go, that's why the name.

4. Does this work on Windows? I mean does pthread_create() work on
Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

patch is updated to add support for the Windows platform.

5. Typos:
tablspace => tablespace
safly => safely

Done.

6. parallel_backup_run() needs some comments explaining the states it goes

through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from server
*/
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Done.

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Done.

The corrupted tablespace and crash, reported by Rajkumar, have been fixed.
A pointer
variable remained uninitialized which in turn caused the system to
misbehave.

Attached is the updated set of patches. AFAIK, to complete parallel backup
feature
set, there remain three sub-features:

1- parallel backup does not work with a standby server. In parallel backup,
the server
spawns multiple processes and there is no shared state being maintained. So
currently,
no way to tell multiple processes if the standby was promoted during the
backup since
the START_BACKUP was called.

2- throttling. Robert previously suggested that we implement throttling on
the client-side.
However, I found a previous discussion where it was advocated to be added
to the
backend instead[1]/messages/by-id/521B4B29.20009@2ndquadrant.com.

So, it was better to have a consensus before moving the throttle function
to the client.
That’s why for the time being I have disabled it and have asked for
suggestions on it
to move forward.

It seems to me that we have to maintain a shared state in order to support
taking backup
from standby. Also, there is a new feature recently committed for backup
progress
reporting in the backend (pg_stat_progress_basebackup). This functionality
was recently
added via this commit ID: e65497df. For parallel backup to update these
stats, a shared
state will be required.

Since multiple pg_basebackup can be running at the same time, maintaining a
shared state
can become a little complex, unless we disallow taking multiple parallel
backups.

So proceeding on with this patch, I will be working on:
- throttling to be implemented on the client-side.
- adding a shared state to handle backup from the standby.

[1]: /messages/by-id/521B4B29.20009@2ndquadrant.com
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

v10-parallel-backup.zipapplication/zip; name=v10-parallel-backup.zipDownload
#56Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Asif Rehman (#55)
Re: WIP/PoC for parallel backup

Thanks Asif,

I have re-verified reported issue. expect standby backup, others are fixed.

Thanks & Regards,
Rajkumar Raghuwanshi

On Fri, Mar 27, 2020 at 11:04 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Show quoted text

On Wed, Mar 25, 2020 at 12:22 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

While testing further I observed parallel backup is not able to take
backup of standby server.

mkdir /tmp/archive_dir
echo "archive_mode='on'">> data/postgresql.conf
echo "archive_command='cp %p /tmp/archive_dir/%f'">> data/postgresql.conf

./pg_ctl -D data -l logs start
./pg_basebackup -p 5432 -Fp -R -D /tmp/slave

echo "primary_conninfo='host=127.0.0.1 port=5432 user=edb'">>
/tmp/slave/postgresql.conf
echo "restore_command='cp /tmp/archive_dir/%f %p'">>
/tmp/slave/postgresql.conf
echo "promote_trigger_file='/tmp/failover.log'">>
/tmp/slave/postgresql.conf

./pg_ctl -D /tmp/slave -l /tmp/slave_logs -o "-p 5433" start -c

[edb@localhost bin]$ ./psql postgres -p 5432 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
f
(1 row)

[edb@localhost bin]$ ./psql postgres -p 5433 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
t
(1 row)

*[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs
6pg_basebackup: error: could not list backup files: ERROR: the standby was
promoted during online backupHINT: This means that the backup being taken
is corrupt and should not be used. Try taking another online
backup.pg_basebackup: removing data directory "/tmp/bkp_s"*

#same is working fine without parallel backup
[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs 1
[edb@localhost bin]$ ls /tmp/bkp_s/PG_VERSION
/tmp/bkp_s/PG_VERSION

Thanks & Regards,
Rajkumar Raghuwanshi

On Thu, Mar 19, 2020 at 4:11 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

In another scenarios, bkp data is corrupted for tablespace. again this
is not reproducible everytime,
but If I am running the same set of commands I am getting the same error.

[edb@localhost bin]$ ./pg_ctl -D data -l logfile start
waiting for server to start.... done
server started
[edb@localhost bin]$
[edb@localhost bin]$ mkdir /tmp/tblsp
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace
tblsp location '/tmp/tblsp';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create database testdb
tablespace tblsp;"
CREATE DATABASE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "create table testtbl (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "insert into testtbl
values ('parallel_backup with tablespace');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp -T
/tmp/tblsp=/tmp/tblsp_bkp --jobs 2
[edb@localhost bin]$ ./pg_ctl -D /tmp/bkp -l /tmp/bkp_logs -o "-p 5555"
start
waiting for server to start.... done
server started
[edb@localhost bin]$ ./psql postgres -p 5555 -c "select * from
pg_tablespace where spcname like 'tblsp%' or spcname = 'pg_default'";
oid | spcname | spcowner | spcacl | spcoptions
-------+------------+----------+--------+------------
1663 | pg_default | 10 | |
16384 | tblsp | 10 | |
(2 rows)

[edb@localhost bin]$ ./psql testdb -p 5555 -c "select * from testtbl";
psql: error: could not connect to server: FATAL:
"pg_tblspc/16384/PG_13_202003051/16385" is not a valid data directory
DETAIL: File "pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION" is
missing.
[edb@localhost bin]$
[edb@localhost bin]$ ls
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
[edb@localhost bin]$ ls
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
ls: cannot access
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION: No such file or
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 6:19 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

On testing further, I found when taking backup with -R, pg_basebackup
crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test
values ('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D /tmp/test_bkp/bkp
-R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D
/tmp/test_bkp/bkp -R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at
pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the
patch to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends
out pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

Fixed.

2. With parallel jobs, maxrate is now not supported. Since we are now
asking
data in multiple threads throttling seems important here. Can you
please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested,
let rename
SEND_FILES to SEND_FILE instead.

Yes, we are fetching a single file. However, SEND_FILES is still capable
of fetching multiple files in one
go, that's why the name.

4. Does this work on Windows? I mean does pthread_create() work on
Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

patch is updated to add support for the Windows platform.

5. Typos:
tablspace => tablespace
safly => safely

Done.

6. parallel_backup_run() needs some comments explaining the states it goes

through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from
server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Done.

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Done.

The corrupted tablespace and crash, reported by Rajkumar, have been fixed.
A pointer
variable remained uninitialized which in turn caused the system to
misbehave.

Attached is the updated set of patches. AFAIK, to complete parallel backup
feature
set, there remain three sub-features:

1- parallel backup does not work with a standby server. In parallel
backup, the server
spawns multiple processes and there is no shared state being maintained.
So currently,
no way to tell multiple processes if the standby was promoted during the
backup since
the START_BACKUP was called.

2- throttling. Robert previously suggested that we implement throttling on
the client-side.
However, I found a previous discussion where it was advocated to be added
to the
backend instead[1].

So, it was better to have a consensus before moving the throttle function
to the client.
That’s why for the time being I have disabled it and have asked for
suggestions on it
to move forward.

It seems to me that we have to maintain a shared state in order to support
taking backup
from standby. Also, there is a new feature recently committed for backup
progress
reporting in the backend (pg_stat_progress_basebackup). This functionality
was recently
added via this commit ID: e65497df. For parallel backup to update these
stats, a shared
state will be required.

Since multiple pg_basebackup can be running at the same time, maintaining
a shared state
can become a little complex, unless we disallow taking multiple parallel
backups.

So proceeding on with this patch, I will be working on:
- throttling to be implemented on the client-side.
- adding a shared state to handle backup from the standby.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#57Ahsan Hadi
ahsan.hadi@gmail.com
In reply to: Rajkumar Raghuwanshi (#56)
Re: WIP/PoC for parallel backup

On Mon, Mar 30, 2020 at 3:44 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Thanks Asif,

I have re-verified reported issue. expect standby backup, others are fixed.

Yes As Asif mentioned he is working on the standby issue and adding
bandwidth throttling functionality to parallel backup.

It would be good to get some feedback on Asif previous email from Robert on
the design considerations for stand-by server support and throttling. I
believe all the other points mentioned by Robert in this thread are
addressed by Asif so it would be good to hear about any other concerns that
are not addressed.

Thanks,

-- Ahsan

Thanks & Regards,
Rajkumar Raghuwanshi

On Fri, Mar 27, 2020 at 11:04 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Wed, Mar 25, 2020 at 12:22 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

While testing further I observed parallel backup is not able to take
backup of standby server.

mkdir /tmp/archive_dir
echo "archive_mode='on'">> data/postgresql.conf
echo "archive_command='cp %p /tmp/archive_dir/%f'">> data/postgresql.conf

./pg_ctl -D data -l logs start
./pg_basebackup -p 5432 -Fp -R -D /tmp/slave

echo "primary_conninfo='host=127.0.0.1 port=5432 user=edb'">>
/tmp/slave/postgresql.conf
echo "restore_command='cp /tmp/archive_dir/%f %p'">>
/tmp/slave/postgresql.conf
echo "promote_trigger_file='/tmp/failover.log'">>
/tmp/slave/postgresql.conf

./pg_ctl -D /tmp/slave -l /tmp/slave_logs -o "-p 5433" start -c

[edb@localhost bin]$ ./psql postgres -p 5432 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
f
(1 row)

[edb@localhost bin]$ ./psql postgres -p 5433 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
t
(1 row)

*[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs
6pg_basebackup: error: could not list backup files: ERROR: the standby was
promoted during online backupHINT: This means that the backup being taken
is corrupt and should not be used. Try taking another online
backup.pg_basebackup: removing data directory "/tmp/bkp_s"*

#same is working fine without parallel backup
[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs 1
[edb@localhost bin]$ ls /tmp/bkp_s/PG_VERSION
/tmp/bkp_s/PG_VERSION

Thanks & Regards,
Rajkumar Raghuwanshi

On Thu, Mar 19, 2020 at 4:11 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

In another scenarios, bkp data is corrupted for tablespace. again this
is not reproducible everytime,
but If I am running the same set of commands I am getting the same
error.

[edb@localhost bin]$ ./pg_ctl -D data -l logfile start
waiting for server to start.... done
server started
[edb@localhost bin]$
[edb@localhost bin]$ mkdir /tmp/tblsp
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace
tblsp location '/tmp/tblsp';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create database
testdb tablespace tblsp;"
CREATE DATABASE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "create table testtbl (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "insert into testtbl
values ('parallel_backup with tablespace');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp -T
/tmp/tblsp=/tmp/tblsp_bkp --jobs 2
[edb@localhost bin]$ ./pg_ctl -D /tmp/bkp -l /tmp/bkp_logs -o "-p
5555" start
waiting for server to start.... done
server started
[edb@localhost bin]$ ./psql postgres -p 5555 -c "select * from
pg_tablespace where spcname like 'tblsp%' or spcname = 'pg_default'";
oid | spcname | spcowner | spcacl | spcoptions
-------+------------+----------+--------+------------
1663 | pg_default | 10 | |
16384 | tblsp | 10 | |
(2 rows)

[edb@localhost bin]$ ./psql testdb -p 5555 -c "select * from testtbl";
psql: error: could not connect to server: FATAL:
"pg_tblspc/16384/PG_13_202003051/16385" is not a valid data directory
DETAIL: File "pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION" is
missing.
[edb@localhost bin]$
[edb@localhost bin]$ ls
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
[edb@localhost bin]$ ls
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
ls: cannot access
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION: No such file or
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 6:19 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

On testing further, I found when taking backup with -R, pg_basebackup
crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test (a
text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test
values ('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D
/tmp/test_bkp/bkp -R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D
/tmp/test_bkp/bkp -R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at
pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the
patch to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few
observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends
out pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

Fixed.

2. With parallel jobs, maxrate is now not supported. Since we are now
asking
data in multiple threads throttling seems important here. Can you
please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested,
let rename
SEND_FILES to SEND_FILE instead.

Yes, we are fetching a single file. However, SEND_FILES is still capable
of fetching multiple files in one
go, that's why the name.

4. Does this work on Windows? I mean does pthread_create() work on
Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

patch is updated to add support for the Windows platform.

5. Typos:
tablspace => tablespace
safly => safely

Done.

6. parallel_backup_run() needs some comments explaining the states it

goes
through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from
server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Done.

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Done.

The corrupted tablespace and crash, reported by Rajkumar, have been
fixed. A pointer
variable remained uninitialized which in turn caused the system to
misbehave.

Attached is the updated set of patches. AFAIK, to complete parallel
backup feature
set, there remain three sub-features:

1- parallel backup does not work with a standby server. In parallel
backup, the server
spawns multiple processes and there is no shared state being maintained.
So currently,
no way to tell multiple processes if the standby was promoted during the
backup since
the START_BACKUP was called.

2- throttling. Robert previously suggested that we implement
throttling on the client-side.
However, I found a previous discussion where it was advocated to be added
to the
backend instead[1].

So, it was better to have a consensus before moving the throttle function
to the client.
That’s why for the time being I have disabled it and have asked for
suggestions on it
to move forward.

It seems to me that we have to maintain a shared state in order to
support taking backup
from standby. Also, there is a new feature recently committed for backup
progress
reporting in the backend (pg_stat_progress_basebackup). This
functionality was recently
added via this commit ID: e65497df. For parallel backup to update these
stats, a shared
state will be required.

Since multiple pg_basebackup can be running at the same time, maintaining
a shared state
can become a little complex, unless we disallow taking multiple parallel
backups.

So proceeding on with this patch, I will be working on:
- throttling to be implemented on the client-side.
- adding a shared state to handle backup from the standby.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Highgo Software (Canada/China/Pakistan)
URL : http://www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
EMAIL: mailto: ahsan.hadi@highgo.ca

#58Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Ahsan Hadi (#57)
Re: WIP/PoC for parallel backup

Hi Asif,

My colleague Kashif Zeeshan reported an issue off-list, posting here,
please take a look.

When executing two backups at the same time, getting FATAL error due to
max_wal_senders and instead of exit Backup got completed
And when tried to start the server from the backup cluster, getting error.

[edb@localhost bin]$ ./pgbench -i -s 200 -h localhost -p 5432 postgres
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C2000270 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57849"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (3) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (4) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (5) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (7) created
pg_basebackup: write-ahead log end point: 0/C3000050
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D /home/edb/Desktop/backup1/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C20001C0 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57848"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (3) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (4) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (5) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (7) created
pg_basebackup: write-ahead log end point: 0/C2000348
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed

[edb@localhost bin]$ ./pg_ctl -D /home/edb/Desktop/backup1/ -o "-p 5438"
start
pg_ctl: directory "/home/edb/Desktop/backup1" is not a database cluster
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 30, 2020 at 6:28 PM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

Show quoted text

On Mon, Mar 30, 2020 at 3:44 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Thanks Asif,

I have re-verified reported issue. expect standby backup, others are
fixed.

Yes As Asif mentioned he is working on the standby issue and adding
bandwidth throttling functionality to parallel backup.

It would be good to get some feedback on Asif previous email from Robert
on the design considerations for stand-by server support and throttling. I
believe all the other points mentioned by Robert in this thread are
addressed by Asif so it would be good to hear about any other concerns that
are not addressed.

Thanks,

-- Ahsan

Thanks & Regards,
Rajkumar Raghuwanshi

On Fri, Mar 27, 2020 at 11:04 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Wed, Mar 25, 2020 at 12:22 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

While testing further I observed parallel backup is not able to take
backup of standby server.

mkdir /tmp/archive_dir
echo "archive_mode='on'">> data/postgresql.conf
echo "archive_command='cp %p /tmp/archive_dir/%f'">>
data/postgresql.conf

./pg_ctl -D data -l logs start
./pg_basebackup -p 5432 -Fp -R -D /tmp/slave

echo "primary_conninfo='host=127.0.0.1 port=5432 user=edb'">>
/tmp/slave/postgresql.conf
echo "restore_command='cp /tmp/archive_dir/%f %p'">>
/tmp/slave/postgresql.conf
echo "promote_trigger_file='/tmp/failover.log'">>
/tmp/slave/postgresql.conf

./pg_ctl -D /tmp/slave -l /tmp/slave_logs -o "-p 5433" start -c

[edb@localhost bin]$ ./psql postgres -p 5432 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
f
(1 row)

[edb@localhost bin]$ ./psql postgres -p 5433 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
t
(1 row)

*[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs
6pg_basebackup: error: could not list backup files: ERROR: the standby was
promoted during online backupHINT: This means that the backup being taken
is corrupt and should not be used. Try taking another online
backup.pg_basebackup: removing data directory "/tmp/bkp_s"*

#same is working fine without parallel backup
[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs 1
[edb@localhost bin]$ ls /tmp/bkp_s/PG_VERSION
/tmp/bkp_s/PG_VERSION

Thanks & Regards,
Rajkumar Raghuwanshi

On Thu, Mar 19, 2020 at 4:11 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

In another scenarios, bkp data is corrupted for tablespace. again this
is not reproducible everytime,
but If I am running the same set of commands I am getting the same
error.

[edb@localhost bin]$ ./pg_ctl -D data -l logfile start
waiting for server to start.... done
server started
[edb@localhost bin]$
[edb@localhost bin]$ mkdir /tmp/tblsp
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace
tblsp location '/tmp/tblsp';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create database
testdb tablespace tblsp;"
CREATE DATABASE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "create table testtbl
(a text);"
CREATE TABLE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "insert into testtbl
values ('parallel_backup with tablespace');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp -T
/tmp/tblsp=/tmp/tblsp_bkp --jobs 2
[edb@localhost bin]$ ./pg_ctl -D /tmp/bkp -l /tmp/bkp_logs -o "-p
5555" start
waiting for server to start.... done
server started
[edb@localhost bin]$ ./psql postgres -p 5555 -c "select * from
pg_tablespace where spcname like 'tblsp%' or spcname = 'pg_default'";
oid | spcname | spcowner | spcacl | spcoptions
-------+------------+----------+--------+------------
1663 | pg_default | 10 | |
16384 | tblsp | 10 | |
(2 rows)

[edb@localhost bin]$ ./psql testdb -p 5555 -c "select * from testtbl";
psql: error: could not connect to server: FATAL:
"pg_tblspc/16384/PG_13_202003051/16385" is not a valid data directory
DETAIL: File "pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION" is
missing.
[edb@localhost bin]$
[edb@localhost bin]$ ls
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
[edb@localhost bin]$ ls
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
ls: cannot access
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION: No such file or
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 6:19 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

On testing further, I found when taking backup with -R, pg_basebackup
crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test
(a text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test
values ('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D
/tmp/test_bkp/bkp -R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D
/tmp/test_bkp/bkp -R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at
pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased the
patch to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few
observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends
out pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

Fixed.

2. With parallel jobs, maxrate is now not supported. Since we are
now asking
data in multiple threads throttling seems important here. Can you
please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested,
let rename
SEND_FILES to SEND_FILE instead.

Yes, we are fetching a single file. However, SEND_FILES is still capable
of fetching multiple files in one
go, that's why the name.

4. Does this work on Windows? I mean does pthread_create() work on
Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

patch is updated to add support for the Windows platform.

5. Typos:
tablspace => tablespace
safly => safely

Done.

6. parallel_backup_run() needs some comments explaining the states it

goes
through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server
*/
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from
server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Done.

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Done.

The corrupted tablespace and crash, reported by Rajkumar, have been
fixed. A pointer
variable remained uninitialized which in turn caused the system to
misbehave.

Attached is the updated set of patches. AFAIK, to complete parallel
backup feature
set, there remain three sub-features:

1- parallel backup does not work with a standby server. In parallel
backup, the server
spawns multiple processes and there is no shared state being maintained.
So currently,
no way to tell multiple processes if the standby was promoted during the
backup since
the START_BACKUP was called.

2- throttling. Robert previously suggested that we implement
throttling on the client-side.
However, I found a previous discussion where it was advocated to be
added to the
backend instead[1].

So, it was better to have a consensus before moving the throttle
function to the client.
That’s why for the time being I have disabled it and have asked for
suggestions on it
to move forward.

It seems to me that we have to maintain a shared state in order to
support taking backup
from standby. Also, there is a new feature recently committed for backup
progress
reporting in the backend (pg_stat_progress_basebackup). This
functionality was recently
added via this commit ID: e65497df. For parallel backup to update these
stats, a shared
state will be required.

Since multiple pg_basebackup can be running at the same time,
maintaining a shared state
can become a little complex, unless we disallow taking multiple parallel
backups.

So proceeding on with this patch, I will be working on:
- throttling to be implemented on the client-side.
- adding a shared state to handle backup from the standby.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Highgo Software (Canada/China/Pakistan)
URL : http://www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
EMAIL: mailto: ahsan.hadi@highgo.ca

#59Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Rajkumar Raghuwanshi (#58)
Re: WIP/PoC for parallel backup

Hi Asif

The backup failed with errors "error: could not connect to server: could
not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.
The errors generated for the workers starting from backup worke=1017.
Please note that the backup directory was also not cleaned after the backup
was failed.

Steps
=======
1) Generate data in DB
./pgbench -i -s 600 -h localhost -p 5432 postgres
2) Set max_wal_senders = 2000 in postgresql.
3) Generate the backup

[edb@localhost bin]$
^[[A[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 1/F1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_58692"
pg_basebackup: backup worker (0) created
….
…..
…..
pg_basebackup: backup worker (1017) created
pg_basebackup: error: could not connect to server: could not look up local
user ID 1000: Too many open files
pg_basebackup: backup worker (1018) created
pg_basebackup: error: could not connect to server: could not look up local
user ID 1000: Too many open files



pg_basebackup: error: could not connect to server: could not look up local
user ID 1000: Too many open files
pg_basebackup: backup worker (1989) created
pg_basebackup: error: could not create file
"/home/edb/Desktop/backup//global/4183": Too many open files
pg_basebackup: error: could not create file
"/home/edb/Desktop/backup//global/3592": Too many open files
pg_basebackup: error: could not create file
"/home/edb/Desktop/backup//global/4177": Too many open files
[edb@localhost bin]$

4) The backup directory is not cleaned

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_commit_ts pg_logical pg_notify pg_serial pg_stat
pg_subtrans pg_twophase pg_xact
global pg_dynshmem pg_multixact pg_replslot pg_snapshots pg_stat_tmp
pg_tblspc pg_wal
[edb@localhost bin]$

Kashif Zeeshan
EnterpriseDB

On Thu, Apr 2, 2020 at 2:58 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

My colleague Kashif Zeeshan reported an issue off-list, posting here,
please take a look.

When executing two backups at the same time, getting FATAL error due to
max_wal_senders and instead of exit Backup got completed
And when tried to start the server from the backup cluster, getting error.

[edb@localhost bin]$ ./pgbench -i -s 200 -h localhost -p 5432 postgres
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C2000270 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57849"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (3) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (4) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (5) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (7) created
pg_basebackup: write-ahead log end point: 0/C3000050
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C20001C0 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57848"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (3) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (4) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (5) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
pg_basebackup: backup worker (7) created
pg_basebackup: write-ahead log end point: 0/C2000348
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed

[edb@localhost bin]$ ./pg_ctl -D /home/edb/Desktop/backup1/ -o "-p 5438"
start
pg_ctl: directory "/home/edb/Desktop/backup1" is not a database cluster
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 30, 2020 at 6:28 PM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

On Mon, Mar 30, 2020 at 3:44 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Thanks Asif,

I have re-verified reported issue. expect standby backup, others are
fixed.

Yes As Asif mentioned he is working on the standby issue and adding
bandwidth throttling functionality to parallel backup.

It would be good to get some feedback on Asif previous email from Robert
on the design considerations for stand-by server support and throttling. I
believe all the other points mentioned by Robert in this thread are
addressed by Asif so it would be good to hear about any other concerns that
are not addressed.

Thanks,

-- Ahsan

Thanks & Regards,
Rajkumar Raghuwanshi

On Fri, Mar 27, 2020 at 11:04 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Wed, Mar 25, 2020 at 12:22 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

While testing further I observed parallel backup is not able to take
backup of standby server.

mkdir /tmp/archive_dir
echo "archive_mode='on'">> data/postgresql.conf
echo "archive_command='cp %p /tmp/archive_dir/%f'">>
data/postgresql.conf

./pg_ctl -D data -l logs start
./pg_basebackup -p 5432 -Fp -R -D /tmp/slave

echo "primary_conninfo='host=127.0.0.1 port=5432 user=edb'">>
/tmp/slave/postgresql.conf
echo "restore_command='cp /tmp/archive_dir/%f %p'">>
/tmp/slave/postgresql.conf
echo "promote_trigger_file='/tmp/failover.log'">>
/tmp/slave/postgresql.conf

./pg_ctl -D /tmp/slave -l /tmp/slave_logs -o "-p 5433" start -c

[edb@localhost bin]$ ./psql postgres -p 5432 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
f
(1 row)

[edb@localhost bin]$ ./psql postgres -p 5433 -c "select
pg_is_in_recovery();"
pg_is_in_recovery
-------------------
t
(1 row)

*[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs
6pg_basebackup: error: could not list backup files: ERROR: the standby was
promoted during online backupHINT: This means that the backup being taken
is corrupt and should not be used. Try taking another online
backup.pg_basebackup: removing data directory "/tmp/bkp_s"*

#same is working fine without parallel backup
[edb@localhost bin]$ ./pg_basebackup -p 5433 -D /tmp/bkp_s --jobs 1
[edb@localhost bin]$ ls /tmp/bkp_s/PG_VERSION
/tmp/bkp_s/PG_VERSION

Thanks & Regards,
Rajkumar Raghuwanshi

On Thu, Mar 19, 2020 at 4:11 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

In another scenarios, bkp data is corrupted for tablespace. again
this is not reproducible everytime,
but If I am running the same set of commands I am getting the same
error.

[edb@localhost bin]$ ./pg_ctl -D data -l logfile start
waiting for server to start.... done
server started
[edb@localhost bin]$
[edb@localhost bin]$ mkdir /tmp/tblsp
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace
tblsp location '/tmp/tblsp';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create database
testdb tablespace tblsp;"
CREATE DATABASE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "create table testtbl
(a text);"
CREATE TABLE
[edb@localhost bin]$ ./psql testdb -p 5432 -c "insert into testtbl
values ('parallel_backup with tablespace');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/bkp -T
/tmp/tblsp=/tmp/tblsp_bkp --jobs 2
[edb@localhost bin]$ ./pg_ctl -D /tmp/bkp -l /tmp/bkp_logs -o "-p
5555" start
waiting for server to start.... done
server started
[edb@localhost bin]$ ./psql postgres -p 5555 -c "select * from
pg_tablespace where spcname like 'tblsp%' or spcname = 'pg_default'";
oid | spcname | spcowner | spcacl | spcoptions
-------+------------+----------+--------+------------
1663 | pg_default | 10 | |
16384 | tblsp | 10 | |
(2 rows)

[edb@localhost bin]$ ./psql testdb -p 5555 -c "select * from
testtbl";
psql: error: could not connect to server: FATAL:
"pg_tblspc/16384/PG_13_202003051/16385" is not a valid data directory
DETAIL: File "pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION" is
missing.
[edb@localhost bin]$
[edb@localhost bin]$ ls
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
data/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
[edb@localhost bin]$ ls
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION
ls: cannot access
/tmp/bkp/pg_tblspc/16384/PG_13_202003051/16385/PG_VERSION: No such file or
directory

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 6:19 PM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

On testing further, I found when taking backup with -R,
pg_basebackup crashed
this crash is not consistently reproducible.

[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test
(a text);"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test
values ('parallel_backup with -R recovery-conf');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -j 2 -D
/tmp/test_bkp/bkp -R
Segmentation fault (core dumped)

stack trace looks the same as it was on earlier reported crash with
tablespace.
--stack trace
[edb@localhost bin]$ gdb -q -c core.37915 pg_basebackup
Loaded symbols for /lib64/libnss_files.so.2
Core was generated by `./pg_basebackup -p 5432 -j 2 -D
/tmp/test_bkp/bkp -R'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
3175 backupinfo->curr = fetchfile->next;
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 0x00000000004099ee in worker_get_files (wstate=0xc1e458) at
pg_basebackup.c:3175
#1 0x0000000000408a9e in worker_run (arg=0xc1e458) at
pg_basebackup.c:2715
#2 0x0000003921a07aa1 in start_thread (arg=0x7f72207c0700) at
pthread_create.c:301
#3 0x00000039212e8c4d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:115
(gdb)

Thanks & Regards,
Rajkumar Raghuwanshi

On Mon, Mar 16, 2020 at 2:14 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

Hi Asif,

Thanks Rajkumar. I have fixed the above issues and have rebased
the patch to the latest master (b7f64c64).
(V9 of the patches are attached).

I had a further review of the patches and here are my few
observations:

1.
+/*
+ * stop_backup() - ends an online backup
+ *
+ * The function is called at the end of an online backup. It sends
out pg_control
+ * file, optionally WAL segments and ending WAL location.
+ */

Comments seem out-dated.

Fixed.

2. With parallel jobs, maxrate is now not supported. Since we are
now asking
data in multiple threads throttling seems important here. Can you
please
explain why have you disabled that?

3. As we are always fetching a single file and as Robert suggested,
let rename
SEND_FILES to SEND_FILE instead.

Yes, we are fetching a single file. However, SEND_FILES is still
capable of fetching multiple files in one
go, that's why the name.

4. Does this work on Windows? I mean does pthread_create() work on
Windows?
I asked this as I see that pgbench has its own implementation for
pthread_create() for WIN32 but this patch doesn't.

patch is updated to add support for the Windows platform.

5. Typos:
tablspace => tablespace
safly => safely

Done.

6. parallel_backup_run() needs some comments explaining the states it

goes
through PB_* states.

7.
+            case PB_FETCH_REL_FILES:    /* fetch files from server
*/
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_STOP_BACKUP;
+                    free_filelist(backupinfo);
+                }
+                break;
+            case PB_FETCH_WAL_FILES:    /* fetch WAL files from
server */
+                if (backupinfo->activeworkers == 0)
+                {
+                    backupinfo->backupstate = PB_BACKUP_COMPLETE;
+                }
+                break;

Done.

Why free_filelist() is not called in PB_FETCH_WAL_FILES case?

Done.

The corrupted tablespace and crash, reported by Rajkumar, have been
fixed. A pointer
variable remained uninitialized which in turn caused the system to
misbehave.

Attached is the updated set of patches. AFAIK, to complete parallel
backup feature
set, there remain three sub-features:

1- parallel backup does not work with a standby server. In parallel
backup, the server
spawns multiple processes and there is no shared state being
maintained. So currently,
no way to tell multiple processes if the standby was promoted during
the backup since
the START_BACKUP was called.

2- throttling. Robert previously suggested that we implement
throttling on the client-side.
However, I found a previous discussion where it was advocated to be
added to the
backend instead[1].

So, it was better to have a consensus before moving the throttle
function to the client.
That’s why for the time being I have disabled it and have asked for
suggestions on it
to move forward.

It seems to me that we have to maintain a shared state in order to
support taking backup
from standby. Also, there is a new feature recently committed for
backup progress
reporting in the backend (pg_stat_progress_basebackup). This
functionality was recently
added via this commit ID: e65497df. For parallel backup to update these
stats, a shared
state will be required.

Since multiple pg_basebackup can be running at the same time,
maintaining a shared state
can become a little complex, unless we disallow taking multiple
parallel backups.

So proceeding on with this patch, I will be working on:
- throttling to be implemented on the client-side.
- adding a shared state to handle backup from the standby.

[1]
/messages/by-id/521B4B29.20009@2ndquadrant.com

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Highgo Software (Canada/China/Pakistan)
URL : http://www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
EMAIL: mailto: ahsan.hadi@highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#60Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#55)
Re: WIP/PoC for parallel backup

On Fri, Mar 27, 2020 at 1:34 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Yes, we are fetching a single file. However, SEND_FILES is still capable of fetching multiple files in one
go, that's why the name.

I don't see why it should work that way. If we're fetching individual
files, why have an unused capability to fetch multiple files?

1- parallel backup does not work with a standby server. In parallel backup, the server
spawns multiple processes and there is no shared state being maintained. So currently,
no way to tell multiple processes if the standby was promoted during the backup since
the START_BACKUP was called.

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

2- throttling. Robert previously suggested that we implement throttling on the client-side.
However, I found a previous discussion where it was advocated to be added to the
backend instead[1].

So, it was better to have a consensus before moving the throttle function to the client.
That’s why for the time being I have disabled it and have asked for suggestions on it
to move forward.

It seems to me that we have to maintain a shared state in order to support taking backup
from standby. Also, there is a new feature recently committed for backup progress
reporting in the backend (pg_stat_progress_basebackup). This functionality was recently
added via this commit ID: e65497df. For parallel backup to update these stats, a shared
state will be required.

I've come around to the view that a shared state is a good idea and
that throttling on the server-side makes more sense. I'm not clear on
whether we need shared state only for throttling or whether we need it
for more than that. Another possible reason might be for the
progress-reporting stuff that just got added.

Since multiple pg_basebackup can be running at the same time, maintaining a shared state
can become a little complex, unless we disallow taking multiple parallel backups.

I do not see why it would be necessary to disallow taking multiple
parallel backups. You just need to have multiple copies of the shared
state and a way to decide which one to use for any particular backup.
I guess that is a little complex, but only a little.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#61Robert Haas
robertmhaas@gmail.com
In reply to: Kashif Zeeshan (#59)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 7:30 AM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

The backup failed with errors "error: could not connect to server: could
not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.
The errors generated for the workers starting from backup worke=1017.

It wasn't the fact that you set max_wal_senders to 2000. It was the fact
that you specified 1990 parallel workers. By so doing, you overloaded the
machine, which is why everything failed. That's to be expected.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#62Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Robert Haas (#61)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 4:48 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Apr 2, 2020 at 7:30 AM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

The backup failed with errors "error: could not connect to server: could
not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.
The errors generated for the workers starting from backup worke=1017.

It wasn't the fact that you set max_wal_senders to 2000. It was the fact
that you specified 1990 parallel workers. By so doing, you overloaded the
machine, which is why everything failed. That's to be expected.

Thanks alot Robert,

In this case the backup folder was not being emptied as the backup was
failed, the cleanup should be done in this case too.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#63Robert Haas
robertmhaas@gmail.com
In reply to: Kashif Zeeshan (#62)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 7:55 AM Kashif Zeeshan
<kashif.zeeshan@enterprisedb.com> wrote:

Thanks alot Robert,
In this case the backup folder was not being emptied as the backup was failed, the cleanup should be done in this case too.

Does it fail to clean up the backup folder in all cases where the
backup failed, or just in this case?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#64Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Robert Haas (#63)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 6:23 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Apr 2, 2020 at 7:55 AM Kashif Zeeshan
<kashif.zeeshan@enterprisedb.com> wrote:

Thanks alot Robert,
In this case the backup folder was not being emptied as the backup was

failed, the cleanup should be done in this case too.

Does it fail to clean up the backup folder in all cases where the
backup failed, or just in this case?

The cleanup is done in the cases I have seen so far with base pg_basebackup
functionality (not including the parallel backup feature) with the message
"pg_basebackup: removing contents of data directory"
A similar case was also fixed for parallel backup reported by Rajkumar
where the contents of the backup folder were not cleaned up after the error.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#65Robert Haas
robertmhaas@gmail.com
In reply to: Kashif Zeeshan (#64)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 9:46 AM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Does it fail to clean up the backup folder in all cases where the

backup failed, or just in this case?

The cleanup is done in the cases I have seen so far with base
pg_basebackup functionality (not including the parallel backup feature)
with the message "pg_basebackup: removing contents of data directory"
A similar case was also fixed for parallel backup reported by Rajkumar
where the contents of the backup folder were not cleaned up after the error.

What I'm saying is that it's unclear whether there's a bug here or whether
it just failed because of the very extreme test scenario you created.
Spawning >1000 processes on a small machine can easily make a lot of things
fail.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#66Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#60)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 4:47 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Mar 27, 2020 at 1:34 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Yes, we are fetching a single file. However, SEND_FILES is still capable

of fetching multiple files in one

go, that's why the name.

I don't see why it should work that way. If we're fetching individual
files, why have an unused capability to fetch multiple files?

Okay will rename and will modify the function to send a single file as well.

1- parallel backup does not work with a standby server. In parallel

backup, the server

spawns multiple processes and there is no shared state being maintained.

So currently,

no way to tell multiple processes if the standby was promoted during the

backup since

the START_BACKUP was called.

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP, not while
the backup is
in progress. So if the backup is a large one, early error detection would
be much beneficial.
This is the current behavior of non-parallel backup as well.

2- throttling. Robert previously suggested that we implement throttling

on the client-side.

However, I found a previous discussion where it was advocated to be

added to the

backend instead[1].

So, it was better to have a consensus before moving the throttle

function to the client.

That’s why for the time being I have disabled it and have asked for

suggestions on it

to move forward.

It seems to me that we have to maintain a shared state in order to

support taking backup

from standby. Also, there is a new feature recently committed for backup

progress

reporting in the backend (pg_stat_progress_basebackup). This

functionality was recently

added via this commit ID: e65497df. For parallel backup to update these

stats, a shared

state will be required.

I've come around to the view that a shared state is a good idea and
that throttling on the server-side makes more sense. I'm not clear on
whether we need shared state only for throttling or whether we need it
for more than that. Another possible reason might be for the
progress-reporting stuff that just got added.

Okay, then I will add the shared state. And since we are adding the shared
state, we can use
that for throttling, progress-reporting and standby early error checking.

Since multiple pg_basebackup can be running at the same time,

maintaining a shared state

can become a little complex, unless we disallow taking multiple parallel

backups.

I do not see why it would be necessary to disallow taking multiple
parallel backups. You just need to have multiple copies of the shared
state and a way to decide which one to use for any particular backup.
I guess that is a little complex, but only a little.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup command.
All client workers

must append this ID to all parallel backup replication commands. So that we
can use this identifier

to search for that particular backup. Does that sound good?

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#67Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#66)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP, not while the backup is
in progress. So if the backup is a large one, early error detection would be much beneficial.
This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail quicker.
I don't currently understand the reason for the prohibition so I can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Okay, then I will add the shared state. And since we are adding the shared state, we can use
that for throttling, progress-reporting and standby early error checking.

Please propose a grammar here for all the new replication commands you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup command. All client workers
must append this ID to all parallel backup replication commands. So that we can use this identifier
to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether that's
possible now or not, it seems unwise to hard-wire that assumption into
the wire protocol.

I was thinking that perhaps the client should generate a unique backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#68Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#67)
Re: WIP/PoC for parallel backup

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP, not

while the backup is

in progress. So if the backup is a large one, early error detection

would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail quicker.
I don't currently understand the reason for the prohibition so I can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only intended

to make parallel behave the same as non-parallel here. So, I agree with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding the

shared state, we can use

that for throttling, progress-reporting and standby early error checking.

Please propose a grammar here for all the new replication commands you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands. So that

we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether that's
possible now or not, it seems unwise to hard-wire that assumption into
the wire protocol.

I was thinking that perhaps the client should generate a unique backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any need for
changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared hash
table.
There will be one structure per parallel backup. Since a single parallel
backup
can engage more than one wal sender, so I think max_wal_senders might be a
little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines the
maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains the same
as for non-parallel backup with the exception that multiple threads will
now be
updating it. So in parallel backup, this will represent the overall bytes
that
have been transferred. So the workers would sleep if they have exceeded the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a backend
process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#69Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Asif Rehman (#68)
Re: WIP/PoC for parallel backup

Hi Asif

When a non-existent slot is used with tablespace then correct error is
displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D /home/edb/Desktop/backup/
-T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then the
backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -T
/home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP, not

while the backup is

in progress. So if the backup is a large one, early error detection

would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail quicker.
I don't currently understand the reason for the prohibition so I can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only intended

to make parallel behave the same as non-parallel here. So, I agree with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding the

shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands. So

that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether that's
possible now or not, it seems unwise to hard-wire that assumption into
the wire protocol.

I was thinking that perhaps the client should generate a unique backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any need
for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared hash
table.
There will be one structure per parallel backup. Since a single parallel
backup
can engage more than one wal sender, so I think max_wal_senders might be a
little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines the
maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains the
same
as for non-parallel backup with the exception that multiple threads will
now be
updating it. So in parallel backup, this will represent the overall bytes
that
have been transferred. So the workers would sleep if they have exceeded the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a backend
process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#70Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Kashif Zeeshan (#69)
Re: WIP/PoC for parallel backup

Asif,

After recent backup manifest addition, patches needed to rebase and
reconsideration of a few things like making sure that parallel backup
creates
a manifest file correctly or not etc.

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

#71Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Kashif Zeeshan (#69)
Re: WIP/PoC for parallel backup

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error is
displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then the
backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -T
/home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel Backup is
in progress then the correct error is displayed but then the backup folder
is not cleaned and leaves a corrupt backup. I think one bug fix will solve
all these cases where clean up is not done when parallel backup is failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -j 8
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup patch
then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP, not

while the backup is

in progress. So if the backup is a large one, early error detection

would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail quicker.
I don't currently understand the reason for the prohibition so I can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only intended

to make parallel behave the same as non-parallel here. So, I agree with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding the

shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands. So

that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether that's
possible now or not, it seems unwise to hard-wire that assumption into
the wire protocol.

I was thinking that perhaps the client should generate a unique backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any need
for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared hash
table.
There will be one structure per parallel backup. Since a single parallel
backup
can engage more than one wal sender, so I think max_wal_senders might be
a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines the
maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains the
same
as for non-parallel backup with the exception that multiple threads will
now be
updating it. So in parallel backup, this will represent the overall bytes
that
have been transferred. So the workers would sleep if they have exceeded
the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication command
is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a backend
process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#72Asif Rehman
asifr.rehman@gmail.com
In reply to: Kashif Zeeshan (#71)
1 attachment(s)
Re: WIP/PoC for parallel backup

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16) and
hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable. The
hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand dynamically, I
think it's
sufficient initial size. max_wal_senders is not used, because it can
be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

On Tue, Apr 7, 2020 at 4:03 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error is
displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then the
backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -T
/home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel Backup is
in progress then the correct error is displayed but then the backup folder
is not cleaned and leaves a corrupt backup. I think one bug fix will solve
all these cases where clean up is not done when parallel backup is failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -j
8
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup patch
then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP, not

while the backup is

in progress. So if the backup is a large one, early error detection

would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail quicker.
I don't currently understand the reason for the prohibition so I can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only
intended

to make parallel behave the same as non-parallel here. So, I agree with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding the

shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands. So

that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether that's
possible now or not, it seems unwise to hard-wire that assumption into
the wire protocol.

I was thinking that perhaps the client should generate a unique backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any need
for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared hash
table.
There will be one structure per parallel backup. Since a single parallel
backup
can engage more than one wal sender, so I think max_wal_senders might be
a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines
the maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains the
same
as for non-parallel backup with the exception that multiple threads will
now be
updating it. So in parallel backup, this will represent the overall
bytes that
have been transferred. So the workers would sleep if they have exceeded
the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup as
a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this
structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication command
is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a
backend process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

parallel_backup_v11.zipapplication/zip; name=parallel_backup_v11.zipDownload
#73Jeevan Chalke
jeevan.chalke@enterprisedb.com
In reply to: Asif Rehman (#72)
Re: WIP/PoC for parallel backup

On Tue, Apr 7, 2020 at 10:14 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16) and
hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable. The
hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand dynamically,
I think it's
sufficient initial size. max_wal_senders is not used, because it can
be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

So, are you working on to make it work? I don't think a parallel backup
feature should be creating a backup with no manifest.

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Jeevan Chalke
Associate Database Architect & Team Lead, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company

#74Asif Rehman
asifr.rehman@gmail.com
In reply to: Jeevan Chalke (#73)
Re: WIP/PoC for parallel backup

On Tue, Apr 7, 2020 at 10:03 PM Jeevan Chalke <
jeevan.chalke@enterprisedb.com> wrote:

On Tue, Apr 7, 2020 at 10:14 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16) and
hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable. The
hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand dynamically,
I think it's
sufficient initial size. max_wal_senders is not used, because it
can be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

So, are you working on to make it work? I don't think a parallel backup
feature should be creating a backup with no manifest.

I will, however parallel backup is already quite a large patch. So I think
we should first
agree on the current work before adding a backup manifest and
progress-reporting support.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#75Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#68)
Re: WIP/PoC for parallel backup

On Fri, Apr 3, 2020 at 4:46 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

Non-parallel backup already does the early error checking. I only intended
to make parallel behave the same as non-parallel here. So, I agree with
you that the behavior of parallel backup should be consistent with the
non-parallel one. Please see the code snippet below from
basebackup.c:sendDir()

Oh, OK. So then we need to preserve that behavior, I think. Sorry, I
didn't realize the check was happening there.

I am thinking of the following struct for shared state:

typedef struct
{
char backupid[NAMEDATALEN];
XLogRecPtr startptr;
slock_t lock;
int64 throttling_counter;
bool backup_started_in_recovery;
} BackupSharedState;

Looks broadly reasonable. Can anything other than lock and
throttling_counter change while it's running? If not, how about using
pg_atomic_uint64 for the throttling counter, and dropping lock? If
that gets too complicated it's OK to keep it as you have it.

The shared state structure entries would be maintained by a shared hash table.
There will be one structure per parallel backup. Since a single parallel backup
can engage more than one wal sender, so I think max_wal_senders might be a little
too much; perhaps max_wal_senders/2 since there will be at least 2 connections
per parallel backup? Alternatively, we can set a new GUC that defines the maximum
number of for concurrent parallel backups i.e. ‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

I don't think you need a hash table. Linear search should be fine. And
I see no point in dividing max_wal_senders by 2 either. The default is
*10*. You'd need to increase that by more than an order of magnitude
for a hash table to be needed, and more than that for the shared
memory consumption to matter.

The key would be “backupid=hex_encode(pg_random_strong(16))”

wfm

Progress Reporting:
Although I think we should add progress-reporting for parallel backup as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this structure
as well.

I mean, you can separate it for review if you wish, but it would need
to be committed together.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id

OK. But what if I want to use this interface for a non-parallel backup?

STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label

I don't think it makes sense for STOP_BACKUP to return the same values
that START_BACKUP already returned. Presumably STOP_BACKUP should
return the end LSN. It could also return the backup label and
tablespace map files, as the corresponding SQL function does, unless
there's some better way of returning those in this case.

JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a backend process.

OK.

LIST_TABLESPACES [PROGRESS]

OK.

LIST_FILES [TABLESPACE]

OK.

LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

Why not just LIST_WAL_FILES 'startptr' 'endptr'?

SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

Why parens? That seems useless.

Maybe it would make sense to have SEND_DATA_FILE 'datafilename' and
SEND_WAL_FILE 'walfilename' as separate commands. But not sure.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#76Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#74)
Re: WIP/PoC for parallel backup

On Tue, Apr 7, 2020 at 1:25 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

I will, however parallel backup is already quite a large patch. So I think we should first
agree on the current work before adding a backup manifest and progress-reporting support.

It's going to be needed for commit, but it may make sense for us to do
more review of what you've got here before we worry about it.

I'm gonna try to find some time for that as soon as I can.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#77Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Robert Haas (#76)
Re: WIP/PoC for parallel backup

Hi Asif,

Thanks for new patches.

Patches need to be rebased on head. Getting a failure while applying the
0003 patch.
edb@localhost postgresql]$ git apply
v11/0003-Parallel-Backup-Backend-Replication-commands.patch
error: patch failed: src/backend/storage/ipc/ipci.c:147
error: src/backend/storage/ipc/ipci.c: patch does not apply

I have applied v11 patches on commit -
23ba3b5ee278847e4fad913b80950edb2838fd35 to test further.

pg_basebackup has a new option "--no-estimate-size", pg_basebackup crashes
when using this option.

[edb@localhost bin]$ ./pg_basebackup -D /tmp/bkp --no-estimate-size --jobs=2
Segmentation fault (core dumped)

--stacktrace
[edb@localhost bin]$ gdb -q -c core.80438 pg_basebackup
Loaded symbols for /lib64/libselinux.so.1
Core was generated by `./pg_basebackup -D /tmp/bkp --no-estimate-size
--jobs=2'.
Program terminated with signal 11, Segmentation fault.
#0 ____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=<value
optimized out>, loc=0x392158ee40) at ../stdlib/strtol_l.c:298
298 while (ISSPACE (*s))
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 ____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=<value
optimized out>, loc=0x392158ee40) at ../stdlib/strtol_l.c:298
#1 0x0000003921233b30 in atoi (nptr=<value optimized out>) at atoi.c:28
#2 0x000000000040841e in main (argc=5, argv=0x7ffeaa6fb968) at
pg_basebackup.c:2526

Thanks & Regards,
Rajkumar Raghuwanshi

On Tue, Apr 7, 2020 at 11:07 PM Robert Haas <robertmhaas@gmail.com> wrote:

Show quoted text

On Tue, Apr 7, 2020 at 1:25 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

I will, however parallel backup is already quite a large patch. So I

think we should first

agree on the current work before adding a backup manifest and

progress-reporting support.

It's going to be needed for commit, but it may make sense for us to do
more review of what you've got here before we worry about it.

I'm gonna try to find some time for that as soon as I can.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#78Asif Rehman
asifr.rehman@gmail.com
In reply to: Rajkumar Raghuwanshi (#77)
1 attachment(s)
Re: WIP/PoC for parallel backup

rebased and updated to current master (d025cf88ba). v12 is attahced.

Also, changed the grammar for LIST_WAL_FILES and SEND_FILE to:

- LIST_WAL_FILES 'startptr' 'endptr'
- SEND_FILE 'FILE' [NOVERIFY_CHECKSUMS]

On Wed, Apr 8, 2020 at 10:48 AM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

Hi Asif,

Thanks for new patches.

Patches need to be rebased on head. Getting a failure while applying the
0003 patch.
edb@localhost postgresql]$ git apply
v11/0003-Parallel-Backup-Backend-Replication-commands.patch
error: patch failed: src/backend/storage/ipc/ipci.c:147
error: src/backend/storage/ipc/ipci.c: patch does not apply

I have applied v11 patches on commit -
23ba3b5ee278847e4fad913b80950edb2838fd35 to test further.

pg_basebackup has a new option "--no-estimate-size", pg_basebackup
crashes when using this option.

[edb@localhost bin]$ ./pg_basebackup -D /tmp/bkp --no-estimate-size
--jobs=2
Segmentation fault (core dumped)

--stacktrace
[edb@localhost bin]$ gdb -q -c core.80438 pg_basebackup
Loaded symbols for /lib64/libselinux.so.1
Core was generated by `./pg_basebackup -D /tmp/bkp --no-estimate-size
--jobs=2'.
Program terminated with signal 11, Segmentation fault.
#0 ____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=<value
optimized out>, loc=0x392158ee40) at ../stdlib/strtol_l.c:298
298 while (ISSPACE (*s))
Missing separate debuginfos, use: debuginfo-install
keyutils-libs-1.4-5.el6.x86_64 krb5-libs-1.10.3-65.el6.x86_64
libcom_err-1.41.12-24.el6.x86_64 libselinux-2.0.94-7.el6.x86_64
openssl-1.0.1e-58.el6_10.x86_64 zlib-1.2.3-29.el6.x86_64
(gdb) bt
#0 ____strtol_l_internal (nptr=0x0, endptr=0x0, base=10, group=<value
optimized out>, loc=0x392158ee40) at ../stdlib/strtol_l.c:298
#1 0x0000003921233b30 in atoi (nptr=<value optimized out>) at atoi.c:28
#2 0x000000000040841e in main (argc=5, argv=0x7ffeaa6fb968) at
pg_basebackup.c:2526

Thanks & Regards,
Rajkumar Raghuwanshi

On Tue, Apr 7, 2020 at 11:07 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 7, 2020 at 1:25 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I will, however parallel backup is already quite a large patch. So I

think we should first

agree on the current work before adding a backup manifest and

progress-reporting support.

It's going to be needed for commit, but it may make sense for us to do
more review of what you've got here before we worry about it.

I'm gonna try to find some time for that as soon as I can.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

parallel_backup_v12.zipapplication/zip; name=parallel_backup_v12.zipDownload
PK�`�P? 0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
=x�^=x�^Cx�^ux��Yis�F�,���Rk�&���]9�.������um�.���@�CGb��o��x��(U��LOw���Q0����g������c�&��=�����q�f�osf���W<}:�C�?������C���|2e>���E+�&�x2Z{�����Gn7`�V��>�{����q�N����R�n%�������
���/(�gS��'|����!J}p�~N�[��1��&�����4liZ��� ��6�����x������H�B���_��'�����6_%g�r��:�6�q=�5a��7vQ��GB�J�*�����F��i��8�l��X{-����i�o�{��������j����lO����v�Wk���s�]��+ht�P�x'Q�@������;�������b����.�(���*:(!OFPY2i�s�4]y�o�^N��V�H�$XC�-���.��%�D<Cf�8[�&�����7q>�d�����Y�kW�l�j.�ySR5��&2Q ��$,�HW�}t5�
W?��L�-j���&���O���d.�g�����o��
���P�����7�,��X���Ic��5�j�H4:����
.]_c�d�j=�1M�^ ��E2�a�r�B��hr0B��?�\��}�I�A-�5��[��K�B	�"|���?O�a�����Qve5�DR����.��������]�j0��	��u��������m*$��;�
1!H�0Mp^�5Q���i`��N��CU�8���2��Rk0�0P�q2���$�|�>/O��Hid�����J���yX���7�}H&x���b�U�4���0`����}R�m~�����������$]07���|d��G�9mI2������*�V5�����h��\=��w�\�D��1���7b��G��zp�������l������������������
x�����X��!]g\�]a���l%I���Q�%��n��)���u/�@H@�����#7�
QU���Z�nk�Q�-�"�����
�a(b��K-�:n��B J�9�����-/�l!��@:"l��Hy`��/I#K���)����������&���z8��
���I7��F:'h�cr��ec��{K�MY(`�RR������FqIo'��#��e���K[���e���"E
1Ta��+�F"O��\|��`0X��b��K{$k0���K�ZR�����*A�*�%��q�����k���l�8F~��G�y;�m�x�/��d��1��\�e�R������y^���2���6��y�b���VOL�"7���B������3 &c��<���B/^������a�$`��U�.{
�6��lq}�w�������<y6d�l���xt�����.Q>�:� ~�R���O�S�dt{&�;�Z��w+Cd'W��g�gdM��hNL�`K>��O�D<��e��
�h�n9�Z�jK=o�����Y�]�./���SS��������	%A�'A��4�9Q%�@�
�Dp��"�����BS>E����i�sg'�z���P/.�W�2�E�N�s�gN��{1�qCz����<>�7�>!��n����O�����lF�Y`�P�a�[��$y����Y���>&��	C����=|�����s�p+�q��������S��4�Z.�/���|�r/����[T[�X�������(T�(r��������uE��vm��ZH��9!=A8g�C��C2K�-��Q91���M��f|���/n|j��7`I�&U<'t�U�_�n�����/n����/�������Q�&��m�9
��+�� 
������.���,�r|+EG��8U�Qv���?h��������67�^&�b�q��F���3������|B~!�r?����Ya��,����'�,
]���r#1+�l+����K���:�G��)��o��wA��S�WG������>�n�2��`$[��h��W���p������|�S����fSK�����~��!!0���+&|�v�Y���$��~�����E�X���~S�>��~���\k��|f��^�k���V�����m�����g?7�|���D��B��e�r����h�+Q��}�������������djC�������>�}w�g���cE�?�}�QFg5cot<�:;���������h���Az^�IS7����?PK��+�PK�`�P�@? 0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
=x�^=x�^Cx�^ux��[mw�8��B�9m 2�k�ighB���i�������o���M��t����[L�tsfR�������<��:���<s]����a�����e#�eltzt�t�����srpz���2�i��V�L�G:�V�����n��H�O�, �0������&�x2�{Y�`)?CA���@�N���g��g����V�:�
������q��=K:���A��9i�$�r2d��YD���$
�81g	'1�%l��^z�$�/�B���K	s���w!�'�� y�|�S6�y1�'�n�������W(�W�p1�a.����?h2
�)����i����@U��v4��������et�*6I�OB���MU��P����������%��s�V�@���TO����$Xp���8��C����$v�Q,�}����~� a��o~8n:~����B����S���a�}TZ�r���-�,����g.��%&����w��e09!�������zw��}.�4�����F����?<���m�^��o��:���~�l�[�kwZ'���j����
6Yk��~#�v���ca��O��.�e����h����G����E�a^���"���_y�� {�s�{vdUI�����|���^���o�_���njs���}�h�$���N^��7<�j��k�}���s���_��+�q�~�����E!x.yj�	^mT*��J}/�I��^,�f���C�=W6�c�x�1��T*.K��X:�yj��{�����a,��|�z�F�I�����!��2p'��"t�0y�����k�,��m�W������*H��M�IE�g�"��2e_����/�5�;��hh��\5v����Q�K�Ga��9���`�AxGx�z���0L��\T�J��r������F�l��1-��,�k�`��R�5�9O��1����:������IjGq8�!��Y��v�b6��������Uw�{�=����}�>�����6�{���w�����.�����G�U�1�3HR�O�j��/�\�,_��CH����V��v����&��������VYo���������U{���*h�Je4�}��?�u?���:��P�l��m|/�Rlc����Z�
�D����"�A����d8i�s��c�/���/�_��1Ig����D��C8���x���r�@s�N^� -��;Y�^7f
��~���I������d	��u���O���#�xk���|����v�����������uTK��xy}��j��	 �\4�1��J��~P�?�,!���g%W��c��������K>�Tj<�������3�&��tB�c�?w�$���'���g�<u=�iA�����!��\��/��H�e�A �c�"�J���a0�\������a	v�l��(����u]�y�����������]]R~�h��'�i�E��2����L�3/����q��b�:�PVD�a�$�Zf\I1p���"�e�b���j,v&Pn��5�o�F*�/5��S#v��>*�%���u�aD�1�]ty�-����Oa~�-�7�E0�|�s�sahK\����J�����j_��I�#�(�F������G��T�^�����y�nBd�v	��	,�����m�"@�0Ab4��2��H1��~;d��?}*'`z���j�5�C%D��r`�������UtV��[B��SJ�v�����
VS�^Dp:S��2�\l
�pgf�6���uc]����2VM���f���:93�vA�����WeX���Lo#+��C<�Z"�+�md�U3�����Y����kk�c��E��W�
���IB ;�F�\��hs��d?��-���t��AKN='���A[�[�$+�,EE!Xf�hZt4�� ��Y���}�a���'�?`D�1m��,��	��9o��aRR8�n )��9��_���Hz�����77������nNt�)l6d��E8v�������,-?�by#%J�k�{�A��ga/�Vt��"~i-���t����P
��l��&������g��v���h��OW��/�G��9D)��}�+�0�vnX��C���J���d�����U�CU�2]A�${�H�c�fh����E��'Kj��,#�t�K�(-a�`�5��Z��m�?��%���OW"���9�OW�~Z��������O8P��x�b6B�t{�O�>��^��t[�O�A�9�a�����5\�o�a�W������W�6����^	��/��JL��,��!h/c �l����t3XO7B�r��H/����7��a��@�n����0�n���%���AO���tcOWx�%~�z�
��n����G�w!��S����H�N
�%bW��q{������>�S���(K���gK��b������Q�s0���v��[G�g|�FN�	S���C���rO1(�s����=�c���B��
�����M�[�^��R���Ic"���466���yP*�1D
�
��+��Cc��\r�Z�'j��8!${��Ru�db����l��@M15
:�*^����5��'j�X�7���5��E�U_��'_�����OM������&G���S���C��!S'��5:�@���E�
A��Q��j��o���(l���Tu��TSd����8�_���!w�-�.��`��d��8w���qR�z�-����b�;i&�u##R^�GB����w����g���J^gts���RBZ��x��lVVm<��k�1�m�{=x������-��eg�%1, `dL�waJ&�4E��DC�cB� �7#�((�z���1��		�c����]�������������Y�B�$CxJ	�E�c( d)D�T�3��J����D���Yb�4��<���'����j�+I��$<�
Q���/@��	��?^X	��wK|��B)��(�r�k�D*I+�1K~D<��)L�p��#�R����|�/#��}�oC��Z���0��:�
���6��zy:��t<X�fO���	�
���+*��-���*��_-E�/�z���N]�-�n�a���@(���/�,_`��O)-,��D��5O.��<
�m��<��ZD�	~�#5o=�CQv����qb1j l<��Q��y�Vb�,VU�����1\&�Wo��=o�����]+<��A�����Raf�WrwH�8T��b�EK�/�I"az*5.�@7%�3|����;cf���$Y����VE�_�o /|�,���&!AiERr�,S��.�vq=N�B
P�N@�sq+M^�a���7Y�q�[�{����c3�Ii~����}X#;A�P��%Pfa��"7Ng�H�����+����2�Tm�6p�
4S��M7�7^�4�������W�"�C�pb!�_��s{t#`	������K9��~v���^�f�f�������X�\,�0>�Hx�*��z��"����SG������g�,�`�E����b�`B�}|��x5BG��X�Q!e�mWV�L���m�rz��.��i$���(�s&5�&��67a��� ��VK��9"vfq,������h�oi��y�������Z�)V���1���wb(���\g�[���u��..s�B~A�L�����Bgj��H��52Ypnx��k���������pf�o\��\;�:�<]B�Px����+v�8na�&�a�l
:\(kP�$�,�)�vF&{r�7A�O:V�������.������Q�����-��P';�e����Y@�3��*Gj�F�60�����0��-�I���%��.e�t%s���3]���m.9��'�t�3����8},��&E=���U��������{-�V)hs��H[��
��k�jy+�Je��1V�#��V�����(���z�#�*]���M���K�jvN�5O�G��T�	I-��.fb,�Kv'�s�5����y��fWNt
|,s�X�*W���VS���VEW��-9�<[���(���F�������� +�ClUk[�U�B����ZX���T�M���$���Qi9E-��*%���v+~JKy���� 9�y�F�]���x)]��������-Hi��WSR��6���R�H�Jou�EG��P�E^\�D}xK"�h�-�P�n�<������@�V	���4��h���$��������l
��:T��*���!�e���W����pA�m.�(X�����w��������{p�4��'G'�#�>�,�X.#�0��=���S$����%N��������^u��0�	�
��5#�1�p��m�f�/���"
W���s9�\a��T�r"�\��P5��Ff�u+�����9��!��<�#'�	����
�d,�l�����w��� ��0Fw�=�Y���!�N�s�l�Z7� ��x)��W��PKh���@PK�`�P�7 0003-Parallel-Backup-Backend-Replication-commands.patchUT
=x�^=x�^Cx�^ux��}�w�H����_Q�i���[6�I'<^�n�c8>�-�l�-�����w���9NB������-�z������0���~�ux��q���a��j����s0�t�������8��h��7�/��B4�E�����V��,��f������w:w|�W��C����w5�
�#�E������PM�����d��j����v�i�%���F��_^���O���G�����s�I�uBg6sg�gg�y��������b��������9t9��������u�e�
g<�/�l\{��sj�8����U�L9��bw^�"Sw�g���&#b�3����r6��06�5�e����Y�-fny�>�
Z���ri[�G���G����V|<=��{*6�:s.����O�������9z?�8tE�~*�hzr��_��Q�"7���8�+7���c�~(n�4b�\
����r�j8�o�h������6ub�hO �=�����.zq�t�!�B��jTE���Ui�]���{gj$���9o'���4���0�Q$��xZ.9��hJ��p-k��~�M<xry�;�����������n���q��yq���������������;�37Z800����Sl�tu��'4O���KW�������"�z `��Nq���"��F���T�n��8��]�p�AB�r��n|����X��:x����=;���&��D���{�{�ax��{�K��7����#�|;0�e�h�{���t��������"
G;uv�b�N:~��w�����H����GTS,���@��kD�wE5�'���~^���~���:b�j����g4�}QM��� t��o1����������l9vw|���L��Sa�of��c*��%��K<M�����a��
	*���h��3��lo��co2��W^,�������2e��_��V�i��{���r<�Nk��#��tE�����V����n6��N
G}���`��:�Aj�����}��.��	����,J�{+�����N����������wGg��W��v	~*n�������XR������h�����.�W�PU4��X.dr�����g��}�����9���
���8��0�
j������y�@k���h�<�;��k����'�������z����,Z���q������'���b�d��\N��}����;8.��!���']G>�O������F���<�<����O�6H�z�*�=�V�������a��M��]�%k#��X�!�)�������z�$�{��mXH	/�*&7���m�g2������������X�\v?E���k���������$ibC���	'�O7�����E;�Kd>�^y/�>���_��9}�}	;p��
.�!
1���G �/���C����st�z[������<���t?O�g�R��y����z����n����"�Y�PB�>P.�	�=$d�?����^vA�8;���
?t�5Z��������j���UC����e�x$�2n�T?�_|��>G���4�J<�=��4��pGo��D��5P>)��^� R/���%`u��AB&���E�yVf,H&���fCTj��!����L�e~�;���W�C���Du���@�z�I�����j��/~G���s��I��%A���/%_Lb��<h����yfd������;
@���K��3
�b�%p�v�|E�	���Lkqt!X�`H���[����A��3�������r��7�A�Ox����M�������@f�OT�

���/���
�!(�0�G�1	��\P�Jb��K�����	�M���A�I	���)�D}�	���E��;U��:�5�nE������Rb���������d�������%�*����������a��&���_���}`�B\��l�8<���-Js�e��=��R�\��'��HI5@Y�$)W�j������25��	k���}� XO� �a:!�/=0)E�o�����m7������a]��r���q��;��;���~�o
�p���Gv��\:E���C�D���P���n�
�]	�]4��sfX��.���u���L<q��G�i�+"Sa�
m�BwZjzh����.�[_�t����eTrt�	
hR,�������7I�<#X&��-�E�%1^���q=UG*�WA����R���]j�M�����j$5ii"�n���>	��(����8**[IQ�Z���g��fI��?(�#�������+�.}���"q���%��DR���# zx���ge�*��6F-�v0@�$[b�������2M�)��&)�9����9Z�!�hv�p[m�r����TR%o���'�(���`�g��G�u�B�������,~��Kr.����yh3��c�K�N}������w��7%�!�H���w��@���wA@#��N�u�K������|�+������:�;zs$;�(��P#�	&��D��or�G,;�����j��m@Z��Tp�8��Pq�Pq$��S�wXVD�*	�S�[E�r����y�.�����c`���� �'�N/`x�7<7�<��5�����l@�O���������>���L�0�BY��S�(T�����
�O��4�
�y�Of�����xD%���7<�o�	�a/As��@8l����� {����>a<�������h
���-�.
J�}�1������2�`��$@���h����4������0�S�+�,���EU�H��,BJ���o�DSYm���!����5��B�!��&�ROr-BY�YO@5��9�������76N������H*�Ey��K+��X�h��h�d�$�������q�LId���/y{II���a��
���9����D�w�� �,�~ZC�(i��-��m��8(^�a��bF��@���\��I���O�z�l�:bG^_����W������{v��|j�.��JX�9�92�9���: %�����M�����Um�e|���3�`�����B(_�����������>�:J�����a�U�Y+������6A�����MF������Gk�w�7o���h���x�mT��������x������RuRr���Q)�M�8�F�`2�2�����{C��M�����(An����9u���������"�;/��#�b���7Gok��?�;���_��=��R����vm�IT�f�3i �I���76m%�V*YDv���^?�k�V�^��A�'0q�� ��(��S�\]�)�����r����
.��\��AeK��)��9�v;������H(��/ ���������U;'�
Q��"����z��)���d�7�.P��t��#X����X��;�M ~Z������6Bq��w(�@�y#�[I >�+��I�
8�I�Q.������B'�7[��a���y�$����!��j}���`����Mnt���~�R
$����P������2I�@^	K���D��2���J;@Rm=�����������hvj��w���o�M���[8$b�X����E�d�plp�N�kw�f�
���E�mcK<'*SE�{��7u��C���l��]r<6T�����m19P��������a���V
|||~��?�
�����.&�|�d�+�����l�ON�]�������7g�`$-#x�����S��%��K3pS���2/[u�eCS�wY���Z�����e6������Y�d�����s��2'�DeS��a�},p��Z�[X����H�D���{W>������xQ��V����Yn�2�������x2���3^(������#��T8��B�d�J:3`�p��4Rg�^j�u6�>g�"�#�0����W�\�����]p����j�
���L�W����wJ��Y�#CTd���Ip4�=�Az.d��0�@7a�����R�V���.�I�.����3��BZ��2��F�P�|%W�Z���x4M�L�r���������9���)�o���Q�O
��b:,�+g�!�4@Q�VUvn����|�������}%:94hM\��y��-�������k���Y�5~3v��6��&�j	2��
��0}���x�T�Ua�R��o2�����{�q���n-i��X�2~���k�,z���2����0"g[��u)�rB����3]J<~,V�HF�uZ�Z������5���K�8Uc�BZ+��������~A�BM��K�*B�,_2�b8F�����`;�{�no{����3cg5���^%k�Nr����D/W�7��i�[��	j���HQ9��4��<;z���(����3�_�>�t�<����A�����g����O�hz����U��������[[������f��`N��,��
�0��K| ���\5�e���
����%�Vs�����{��k%����$�d��[�M#�BWiH�4w����a��$���}�E`T%�8�H�T1����~p�;���*���j�&[4��qOV!�������s{�H�	���	��Z#p��:�$������tC�����r����rk��`����/`m�	*#������-����;���P�p�-Q��"^���z
���o��m�;l6�������7�*�+��|/%m�ZZ$�I���D��aa�����M�k]5;)x�Q�&��N���l�X�Q��(�>T�R���*����8��>f�
�,f.����F��2F����<���>t<���&���#���n�
i[W���	�����K��6��S[�{��9�!�czhL��h��0����"r��0���I���kRQ,��*<����r����@���4<�yb����I%�� �wc��isa�81�z���{��$�G�*
��q�$���G�J���<�H�sC���s;~}t�bn��`��ff�������q^�����y<d^/�eO��(�m������
%�j���
o����F�~�%f��PU�UA���������B!%A�WJ+	�� $��JY����������c�0���3�u9�W�zn����f�b�t�f_���;&0��b�t]uWW�a�rt9�Xri6��[Q��U�Bog�b

j=Ky�$���vd�@^@^<r2JY�E�c������g}4q�J���A��6U��P)uR�L�V`�<�[�Y��Dem�<�s����'�'\��6�S�NC�v�g�g�������%��^���R�����!����e!�����H��3���I���6���������a�q��B|�IX'�`;$K1X0��������'�)�j
e������&�[��N�T(t
C3�0Q��EI�
�����B�D�[��������������b=t,
�������A�D�eG�M���a���y �@C���E=#��D�k
>��w��
����$^���'�+�UR���c�^������Y8}�#\9g�p�����tf	���V�`��o�G��:������}2v����m���h5
����tfj'(h�C&B2�:��*�(��_?)�(6����
�*'��}�k��#aY�eC c��C���^����K%�s��Nl���&6[�'�#�6�����T|����',��������7A.�Et1k��0��-���Z���P_'����8^�hQ�d5��[2��:I�vf;N8�z_\y}��c��������&VP5Z�G�rO��D��8�7)F`b��������|$#�Z��]#}�U�	$z�RT|g����Gc�.��m&�G���g��5Q�g�`
�m����������CR�f���RE��c6k��� ���c������g7����8.�_����kD��m<�@E�j�{CU��������k+��2�^��~Z����Hf&��u
'eC+^�"���^����b/M0v�,��P�q�4Z������a��&41q�d��A�#$by:�N���V�wf���E'��t�'�����T��2V�����D����(kW[-v�Z�������O�
OQ��LXo*(�������`�������5�/�RC��������.����f�I	K���m�{�9�R}n�?K8����2U���>�~_�<�
m��� L���/���-�<�Gt�g��F��r5������S)����6�|�
2���0fb�2�����������Ex.
`�WQ��y6i�]�����,�K�2v�����z���z�)h���W����D�V�Z��-u��:Z��H>�\Sj�NHZ-�q=�����m$.��?�'��(���fS�3����n�8�GL��\��:�)��5H��cO�Q����L�9e��1��F������DW��`�(�i�d�D��s��Q���;���w�������q�jI$��aH��?YD���}NBV�?��a,P�]��r��Y_������;x���5n���j%����#�M����P���=�5�&�N|�_-B4��0o���?���.m���k�������.�G�����WHit���K	��H������4vA���PdO6l���*'3���xy��\��C$R�H�M�o�����0�I�[��C�d�����y�t��=LWM$UI��50(��i\|��RvK�:������XD����a)���"+C9�C�
4X����
�e�������]1�h%�rF9������XeT��l�
������D.��l�Tv�'�8t/@���R'G&�����$;V���e.����V���d85ys0�s`�������w#���A��47V,���f������}:!1*�`�xA3Iw�����a���e��)S�������":��p2��XN��'�Z����P�B�x��e�SM\c&�/�Ea���.�P��5�\R��?�2�3������H���gn��P�'����NG�d@6}��6{�5vNXa��Jz�lV��������
��!9�����m�2�u�L�h���4�[�P���(	�y"�!��(P��5GBJ����c!���g�Pn�EK�&(������XI�b�l�!>�f*Oq-�F%q������aI�K��)�����$�����\r�6�r����e��Kg�0���V�Pa��T�\���
P���n���2��|��?>�����K4=��c��������`�;���������!�sS� �)����H�2Y�m����J��P. 3����M*=���e���^��8��1������R�#b���1�-�dV�li���GP��{�li��e��y��y*�u+���}�T��������y��<HJ	)�%n|vocv!��r��4C�IAl�^7��Tvn����?��_�n� �y���w������y�zR��1�Y'`%��H����@����D�l]]�K�8�%�-i�2\��I��k���9�C �p:�����t*�u3|U�>^���L�� .��CY�!r�8��4I�P��Lr���=}5�rO59F7%��t�����L���-b�`����3-gt����#�}�������I9���$"�lA8VY
Q���-� ���7�
TJ-�E���6�s� K�"�d�`���0��T�����%?F�p�)�#���D��D�Vr;6of���6�;���������#�3i�PV�����Q2��=����i ���[$z�� l)Cf:oQ������X����+�����$�y�.���������HG0�Bg����C�i�(��'�M��TzlCt�k��\�6EG���$����M�"���L
b����lb�dH����^P�Z�r�\��h�`�k*���H����e�"&'?u���K�6���v�3����%���~����2�|�:���	�:8��U'�
�K��n ��2
�k���������8��'�jPB��
f w:�����i2�����X�B��C}|9��i��{Et3�x��#�����7�]�Tg�S�:|����/`��

�q�C�Xf3�K���3�
V��UoDL4�����0�Z�P��k�����")�����^���2?vB����OaU*db��!��K%�.]�Z��P��r�
Et�Y���r6&��ou��x��&�g�MZl���Au=_��.���;��	���=Y�i��m\�b�����}'��������"�lI��l����p�o
2��[(-E���i^�L%�4���0�.�����z�����t����n���QT�ci�Ux��:�e9k������\�,tn���0|���	��f}S�0}l����-{��l�^�tE.�����SUZ��`/�>���w�<��dWj���T�J���s���H�
"n��L�S�hne�f��\����a��X8����7�n��h�x�MG�/(MX]��N��$��'x��O��"m�ScM�N���v(��d�	�Z8��������Lq�m�|�r	�PUJ��jgMg�����o�3KL�_ ������<2��La_,c�BSpm��E$o'2mnB�C^F+���W�K<��l��fv�(@����R;:��������
�5M��=e�eIH ���@����= �J~�JK
,��i��"v�B4��Z�G��8=|��SG�U�5Q4 ���b�'G��������o���]9
�}��iA�c���Z\���k1��z����4~r.��=������+���D�:6�[��?���wv���RH+UHT�d�����(�$|��5���r��8Y����\A��Z��{����d��X�|Tyr��w����V��^������=�5��c�l�T&K�N�nD��hqc��f}N'���`s
s�cc��s%s�Y^ya=��������h��7W�i����x��nH~���s)4�����*�~eh��|�=���sy`�&�n�
�S����#b��:U�W�\-�hGF�����PsO�R|vo�����1�o�J��EK�jb25���?�(�r��@�|~}u��AgG��l�9B��b�c�RE������������d=������90�c4�9�4�l��(XW���qE�1%}/����B2����������m��\�����S�J��\'�m�1v[��z}�}p0:M�z�������.I����i�W,�������Ch�>��EU�Q������>h�gGo����c�c;�����\�/�����t���+Jni7��n&��	4��u~L��������+z�^�d���S+���c��[��Ypf�>�1
]�����l�q,�O��r3�n"��	P0��M47\X�!�Xy[��zb�h���t���-�����D���T��MoD�RTS�x��jh����d�z��%�����z���e+>�^`8�]m��Wv�gj� �QQ��y0����SU�n�yVT����WF#/��E�E�*H�oy������i�2�E
��{ �s�/`�v��t�V�R�~qB:����;��
J��c�����'�o�(��I��&�oo��t�H�5�����G?wO��_iY_l~�^���������Q`�����wG��'j�����AW<����)T���E��C�t=&m�Q��|3��9�DeVXX�T*����s���g��3��|$���=�\��+*�eP���3�8o��������,[����mCO�$,�`�(�CI}�<�������^��4m���U����-BR|�/���}�v�A�L�*�L�����0�|~���f`�c�!���.H���R7�z�u��I0.��;�����d���S��MI�GLNIy��
�q
�%H�;��^�}������������������=��B����^*Ub5b�t�4(��%ib���>�e��	�������>�6
li��&��2��d�[����$��[����jH��+��6s�����	����!�[k��P��@���a�y' ����~������)U @�
L�A`���N=��l������!�&�����SW`�J%���o����]@X�l�y��j�j!�~�FXZ�2��q��"���t����-�ur�����n�hnA��p����?�*��H�%[^[��+H��h,jI���������b(���j���av|[)���R�����be����,&[���.���~�bC��E�t����u�p��8�Rpf,��Gy,��&���/3}'�S���$��tl����
'��d�w$�k��r��S�"'����/����������\�%�M��J9��e��R���������}f���YeO���P��]�M��j�Bq��a!��|+�/���l��I��C�,��X�/��5��t�����zqQwZs}H��$s�Y���oK�[��J�!��=gT���3��C&��Q�;G7)}����e`���!-�������SBKry��m��*���4�(�yi^l�����C�O������(p
>����E�����=��U���sP?�S8z}~qt�A�}���O���o]��z_�yfM^������c���r��k��2��>��K�Jyg���'��~��i4;{���9����4�������m��.�'��Y��{H:��U�����.����B��k�4Q������-�d�l�h:aO���0��e���,C`��m$�(SA�YcA�ajCm��e���kKOv����-�:���ms���Fbm6k��f�Y��3z^���|w��o1��^}���l�����N�9�4�u��}���l\6��:��,6��t?���z�������XQ<w0
��������n9�O7��b&������e������y�TCv!E1s�>��t�v� ��<E�\��/���������D�8^����������2�L��U�+|�����@9��Xoy�������",�^�w e������E�U�i�0d2v'���{L����`�������1����0R�q"���?�.��K]P�z|���z�b3���N����������NLa������42
''�6��%��`�OD,�>��r����z�����4��^o�������d�uq;f[��$^�v�I���\coc�0h����K%����j|z�
�zY|K�&�2��6t�+"k�(d����y�~F�Z����P<�����Z�o��<��f��y?x�D�cNP�������&0r��v�����PNXy����RIf�5g\�!�`)P��W����]*D&�fJK�M�,��"��B��bw/������lw���eg�>���8��[�\����)'<��[����o�+r+
]��s����I�n��$�>���_��J�%�W���!���6C�ef��n��8ME�� `kP����}M)�����:���-0��+/�n������PK�3�)=-�PK�`�P��( 0004-Parallel-Backup-pg_basebackup.patchUT
=x�^=x�^Cx�^ux��=iw�����_1V�-�\�E����,��ZYR$�N����$(�	-�������`I�J��K��f�s�����mL��pg���[��������pg�b�j�6[����l��l�����`*.��h��V�G��V�]~���~����{=q��{~4C����wu}4����'v{8P]tv�_�e��i��nok��i�Zk��*_���a����_�(67vgN��������f>
1������r�h2���;�#_�"tg�7tb�d	g4rG��R��NGf�rt��D@cl�h>�a,�A(�O� �;��G�fq b����}�,�b3�<��Wb2�c���SX#�5�%@3�=�����������#|/�E0c�w#1�
C�#7����4��-<��� �q�H�1��n�J0���	��*�xpz�1�8������r'���Q�Cx����x���S7l��FYD�pc�M7,T���C��h�wvE-��M����3�rGu�n�x��	?�Z�.v^������Q-�G�x[r���7V�d�Z��7�_`����Awkk��������;\k{s���eX��s���h���mQ����~(��������k� ��B7��������w�����uF��WF���S������AI=���b�#�[��6�!���;r�"���0�3��	/��[% h E��P<�83h��~4�gN|�Z������J�y���}w
��c|�M��~3����e�V���f��]���b��G��%!�s� xp��Z^��Z^��o�r�1�b��3��n��&�o$*��	�/��3�VUT41%��r������4��Pv��`�*�UK�|�-��\����J��_���|�x�����/�7��u;%B���	�k��� �#"�����s�l%���c�]�^��p����
Xh��7�i�������vo<������|"�12i=g��o�������G���C���)��lS|h6��<=���?���3���N��^&�J�� qa ���7z� 2��%>�����R��2�����]��Wp���������p���&ry�m�b���Y"���1;���d#�������K��4�F�2��)
��/��m2�[#Y�w�gW�2�Q������ ���Fy�dh���N�[������I{���s�����R�������h/���T������D�.��F��n<�������h�K�|���P��O������_0�������o��?\��?:9�<�?>����K	�y��Pc@q���=�������q����;c����7�����2`��]q�D0;�
<��
��u|$4�0"��j
�-�8��
i��:��#\�g &�:��Z�������K���KqkYx����@.��
�0���_`��!�p��1�1x��'�8�3L�M���eT���-n���K�����R�;{�5�}�y2��(�Xga�zX�����`��r�����}������Yo�Q��z�c`����/����C�Q�2��1I���U����s�V��������%}/���Y|����)v+|�K$�:��9�������3� K��+�H� �\���oL�q�V����0��C�|���N^!��&6������2�
3+�Tu�B�peapKJ� �������F	��3P�GY�@�h���?i���������,V��|���2V���3	�J�� �������lo�;�4��^�`Ww$q������+�,A+�[���pv;�0���u
�ISWnlr��U�&p��k1z ����=Y����j�'���~8�V�7���+��/�N%{{����u7nBS��s���z��$���Dq0�#��Gt����"rRD�,8�d$�r��W7����@XS��h���&�.��'X��$��-�������)0���u
P/
(Kn��:T��&$��3�$��%�������M���Tl���P��q;T�=.�)�9_�8"�J$������k���qz�%�_��I������n���<gi'{��IsR�i2��U%����E���~9��Oco�E���{o����m���)��	��5Q��5H��t�����J�����U�d ��J�"�k4T����M4�D{?����l�;[��.�:[�������'�'�0�2�@fh�����Dx5���H�jP�Ou�
h�G4s�X��I�D���l��v�� ���<"���q76g�_���(��z���p��7`�����s<RIw������q�w�0w�������%�h�H^��rM�������`!
�_&]��K�Gc�c��y<��4`h�LE�KZ;�E�v�
���rZ{:�H���aC�x��D�!��.���9��>��N��4H;?qQ��Q�����y�
���kJ����]�&
����"k�>��/��o��$k�@����ip+MI�5� u*����C7��SnMA��~b+/e/z�'|�����g��Z��8>�G��/i�2�i�`{��UH@h�I�E�JQ�����jg�
��n�����*z��Dr-A�}�AP���-��3�>A���X��d%x����7.���y(l"5ci�^��g�:9��*�bw��5�B�A���u�"����:w��)���r]����@:s<N��
c��������`8<*����O�8����RM�*��|C����+��h��DD.����v�m�����go���'D�(v�5s���3����&����2��	���'�$�^����F���d��v�'�+���1�xu�\no��������g���yrx(��L���2��Hp�^W���N����4gf!)9t�Y�Q�'PO�c�{B��nrP���_�^�=�d��a�xw���ni~!Y5�%r(�!Z"�f%��"�$�R���L�D���
��m\0{E����P�����y%�Ad�E�u��y��47�E�������u����9�SF�4�d��M�Q,�C�~!�&��bm������k������2"q����L#�O���kBE��6+O������Qu5����Y�����1p��l�!�EV$�
�/$$Pf�[l �/�W�X��,�|Ct�K���y����h�^y���,�C��h��y��]k"C	�B�j���@�������V�M����D!i��������8��U�j�����!"u��
��ePe�.�AQE�����+?8������y�(��;mP�j/6[�5=�a��E�Hl����2��|
77)vJ���udl�$�p��
��rE�{f��#�U��!�(���5��y��Y�`�G}�
&�[�����!��q���p�2��
~�����q�������>��N��E|��:��s�=�:��{���]�l2w���*4-�g�\>]r��v��D���<w��a><9��F�+i>w ��@u
a�\��{^�4I;;�!�C]����Ic)��������O[]��h��(v��L�_eh�5.���@:b]�IZamOl�;�Y	���,����t3G���N�g��LB�K���[]�;U�����(����������W��"�����'����yz� $�~��f��vy;w����-��p�f2�i./����0���Q�.!�MB�����~��6��pV_�quS��<��<�w�������A�>z:4j2��������C�a�nf�Y������"��V���k�|A�?�4�)�af{�[��,X]��I3C�S:�ER�[���Zt����e�K�)�|R����XO��ZF�]Z9��w
d%���6�XCr&9��9&i8�;�4�8�:��tt��5�;����D�U=��B��L�	�a��LT?�z]m��
������0UMt��\�A�
����e�C�_s�/W;a��e���(=��Hr������RfRf#z�����^�=$�g��6ec�'�&��n��+j��v��yQDE�����{x��"�x��>���$��_�����������!�:W�C6��
	4����w��J��V����{{B�Qa��n;U���E�M��_\.��T
F�NN?�]�������kn6�����:x������l����~��B�����t������xx����/`��/'�>V����29���%�e:���L��}�Oo�l��N����:w�������j��v[�~�vkxR��y���iU�h�/.��/�vy�����U�)A����S��Os��
9��"�[��~gF��#C�:[�B6��.�8�`xP�>;����*��}M�1��!]��VH?�P�_7�����]5BWxv�.�s�Y�1�~�N.��"���RZ5��=�_t���n���E���V�Hmj8�(�a���c,{��h�a��|M������X$�hy�-9b���n��f�����:�_�X������k���5�1���5�x@ ��!��I���OIR+�dr%|�������?y�?�[�0�?4z�����G�GDX'����~�!�� ��f���_�
�����bDq?�5�a-I��6�dX�y���3Q*E���kO�_�z6l����-$�s�;���1�D�ETa0�nZ�T,���g�"dHb1�H��A�H���]���N�'�M*y'���qp��.��9��fjJ�,(k�g��>�0����lF�Q��]A��z)<�=`f�g`C�Jx�Z5{�Y�@$4���{�l4�T\!����#]F��=)���i
��q�8/(m��e�?	nS\��u���a	�M5�����~Y�R����$�������F��!#�(D���	0�mO��������h*TVA2��I�r3��k���F�M�cD�7T��S�(d*wy����{4�����1�����L'��������A�8��a�A�kj2#���}F Z��hD4�1�	��wMU'��t-Y]	�ZL�����~e*F��"+��mo��K[m���8Q�X>m���B�a<q9X~p���K��L��{kct����V<������IJ��#���o:t<��Sg�D���Zi��C:�%X9r&�F
��i��i"Uq������VJ]�J��]��5�*���Q] %�%u�t'�0a��J���0�'<�
Z�3 �����bx����	`k���Cu8�K4���U��zf���?Q�|��=_�a���"g��C�)��	�T3$�M_b�/���4>s�������s����h�]���c�6.S�_>�>��d��J:�	�k��B".��~%�N���,!_J��J�����YQ��g�4`��L?�������7��7���@����.�J������� MF��%���dMI~RR��c���F�G���#�'}���"�|8�$��@j�p���t�;��������#��-<g�6�����LBXf��X*��~�8$��'l?��6e
*l%�����H�GF��e�a�"�R�d#'J7^�L3y<��>i��x�|�"d�@-����8�9�a�0�{nC��������K�J�Q�o]������S�������S��F6���zAL�[b`T.��jx�>�W��.���SL��xt��p�Og�
�[-��G_.�9��P�*`Z�g>Xp���5����9�Q���}�[�T�kp�M~��L�Y��O�����sOg��5LlY�p��������V��>d�e�C�:[����e�Sq�����5^����1fq�)+<,����M�m/��_�.{?���������z��uo����z�o>�Mz��u�O����p��L���g��>U���m���4��b��+C�?������]����JC k����-�b�����n���]`k{llI|�����S�,xr�Bd��1��aK���	��s�\���:���zgw�U���|/e
�z�����4
�;Y���%�����K�?h���\��qbYb�
fC��M��U�+h�I�q3%��d_O4�*�5�hX��Rd-+Uga}�����?�0��K�t��]YK�0���8����������t�(������}�O�9����w?��]^��vw��2D��N������gZ"*��E��5����s������b���!�)S�����24��&zs�XN�/fX����A2��IrpY�f�)�RH��A?l$�����c����z:	f���HJ��UD9M	v�[LK(���O�:8d�����dm%'��)6����~�~�" ?�B%K�vA���*#�I���:���^P���@�$����|b�d�x?�`���X�M�aL
�n���b��i&��`��bU�e�qty�G}f#@�!��P7��<��E�[�f�,���������2_��)$���Py:���Gk��qo1J)���!�*�Ai}$�����s�mc���8��x|��f�P��N�x�
Y��y�NQ�N{4�IZ��Qm0.?S��!��0��=�2����$���J�|#��V���e`�jb�WMc.tI�!O���T������R�9"��@YgoJ�D7�+P/&�k>	uc
\���BeE/4��7���s�4�Dr�zI�sz?�)��G?Q��~o�Z3����]M��6J����h�*n�	s��4 �X��4�Ll�z�@��s�MU���qT�������,|�6>�J�z�w!��@����hc�J0��=7%g�DM�&!�80u=��	$�b�j(a�����9B&�I�N������F��S2?��F.���psR�,�����|��X���X'�1�Xc7k��(y�B!�2�j�x��+�c�|0�D�M�s����Ry��Z`�2�V�3�������k�>�������a�6Ij�����8��9n�0�������$4�|:�r�xy���{��)K���9�}�0pF����,������qH��!�+�
��Pr�X�`����j����`���DYL�/Y�:��$����!}v_&l~J�n�F)��9������gPB�'�����j�Ny���I���>��$���.�TI���v��0�uw�����m��Rp�q��
�k��,�.g�$�8
#?*��
�S Q�DJ=t4Q��j�������g�����I�I_�R�x*e)��v�����jS�.�b�
����v��<e�]����d�v9c-cH	�����'.��y��Fg�x��RT�G��9<+��|K��M��p�.��b��^�d�������3����+�b<�48HBM�*=�f��!SXUzd:^��um��^�����#e'������������s���j�1&�����&	���Y�OU�V��
:���n8�!��6^q�v����J�Y�l��G���*���g��W�1M���R�U����-a%M�
��F�8�v*VX�A�<�=�O,9���������\�U�e`q�T�E���f2��p��v�vVA;#�Arn\R�V%V�#��r)��q^�6�JB�M���BjdMA��5@J_$
X�.U9K~��6���T��>��hN�v����P��\�����U
AU�'Q���� �M���vb/Vz�*	v:1�qB%�39��$���F0���LHP8�$�8�"��Q��b����<,�n���:|n�/
����r��������H���� ���P�B�r�-{���
'�bi������9�Z.�B*�� �T���9r�9j�����!�4L8���6������TM�P�2�.mZ5��Aa�
����%E9FY8��S�1���4��������e���Y|}���_��)���F���]��#��������[���	���_�0�T�-���n�TW���k�����=�[*���^�
L�eI��:�e]
��0#Su�$�z�t��vNL�<����l"���/�~�����`�N�������O�A	�,`�����cj��A��/�Q'&��Xt�C#����f���0bq���dii6"���~e�-�n�4u�t�o�������|�+?�+�I]��o��Z����Y���4&TW.o��F�����+k��!��J�9Z��
+�.��LL���U��Mq����Eim2+�"E��NR�V��JN3j�Ri�[��F�?6�6=vK��:���87mJ����n��1�V�T|��H::�D,oj���c���D�C1���c|%������p�K�)��U����J^���n���������dKn!��~�z,�����z�����[2�M���sK�5�������|�LF��
n���L#R)�rZ����S-d��+�@�-�!�Fzk��d���Y|����a
_u�.X�V3�
�%���]�%3���i=��^��k�+���S���hK9��R��4���e�G\I}P�D������D��z\k�cE*�Cja���=Dd)P��~�n������'+�>X�e�2d�E����t��kHq�%�{E�m�/���X�d�y�cZ��8�3u[�o���K���/��f��Y����*�{E������p�'^��X�8���L�b]�'"e,_�NtMt��Q�{�`��J�[������q����D��q[�Q ?���a���?����-���%}�#2%M[�����S2o��mxp	52
oa��D����e`J�3�"k>'�=��:�Y9���a>�I{�
�H���}H�T�8=������Y����C{����X~)����^���7�I��DW�� j�uJ��
�*�f���rdG4�Z���>�
ne}h+
��c4
�v�����1�U�_!Nt�LD�^��S9��b�|DPHc:��i_[���U#����GX�?����.x|l���<����"m���24���6r����p��[���<u����Cv��d�;`|�s�?}�L8CJ}���m�*�k4�qJ�����Ev?�f��iRRz���&����~�R��,�ehh�dL>��u�R�k��Ag�_�L,P���(���R	w��=M�V��=Qt�����d
�	�� �#������x^���{�M��>�������2�,��a>��GY}�����q����C��Q�d��F{������v�w���������{�&�T�����&���!%�
���N^�t�^�0�W�]�HY�}�z<�����\��pc���F�<�2��������e�f��H\\`/�U3��Z~�#^����J/�Q�LE�9�I��q�����<�<����E��R�~F#����
��7.�x#J���-����LGT�9���G�,H��|+}����/sIv��8��Q	$��Y\!G��e�3nOG�@O������ �1���
���i7k���
�<h"���/(�����/�<lWS��@���d�,����C=W�I����h{�����9�k��Zz�����0Z������s���+L�����#�1�;��4vA9�u��)^�_l4�>
�����`��D�~�tJ����$�#
(_{a�C�������p��1v1G����
@v�L��k��j�Z����.��%1�������p����G'++���xv���IH���X�Pa�A��e�X��
J���\u�$7h�;����Kb�+��DqY`�����0���B;B[Q8����>R�����[��F�U����W")�/��w�t�V#�s?k����|@���Am;+aK��U��k*��<&����1~�'��v;H"i��:�P �AX�2)B�a�b4a��[����;������2�2�:��]���4�IT�?$us���>��
���<�)�3L���*%:R����IS0�pNt����I���7Md�
J^C�U%=]�x�1�9�������R3���Tl�-g��Z
i�m���t��D��1����.�)�4i�'����~��M|OQ����B'����C����z�6�t����o���|-���'-���j�8K���FC�;��f�-*�3,q�����v�\�_PKT����'��PK�`�P�G# 0005-parallel-backup-testcase.patchUT
=x�^=x�^Cx�^ux��<iW�H�����vr����@�����G�����EG���YRT2K��~���V�v2��N���[w���'�?c�6�m�6G[������Ks����9��;��[���hd���{�����z�=���^�v`���p�l��3�c3������3�N��e���3#��.����dgV��l������d���^�v1��[��r~xy�;���|c����]62��y��,�"�L�k�v�]c�N�u{�=#�#x.zb'pY��?lk���?5�gc��������4��#��Ds�UcV��6�m������M&B�;r�nf�����lg<f������}6z����o$�)2j�g�[���t������`���f���u���n
������a��F���7��o�����3�����3�o"������|o�L��	P������g?n�#}m;!�neF���G��(���s_D���O�
���������>�!'���5������ �'�93��
�������%��k
P�F�i�
h��������{�Y������z�P�l�#dn�m�13O�yV���WL�D�,�.�A�W@��}��8�H�������3G m�����������s"�t�?9#dp�?�X���L$�	E(��:!�~���&��B����n�fd��)���|&��,"3D�Az�	��;�34C�3���k�������%��o����3�qn�c��1p�;�N����}C�o;�t��YHs`N��3��F����#�����b�����]�������{�@3,�x�|��#��X���A�`�Nm�p����#�?�
�x�����Z_��I����������=�[���@~:^�@`uZH1�%�AJ��^������|����5����x6<�Oqdm�doX`�M��������y�e(+r�F���D�!w}�nT�p��rb�`.�uV&p��F�2���O�E�g�J�`����"TXN�J����r���4c;~��d@1YaB45#�������Lt
���� �%��4���4�l!�7�SPM0�+x�,��g�����������3G ���Q�0h0�8��|����m��Mt���S'CA���������P����MX8������Lz�Dt+IN�>d�����&����r!m��@�5*+T���v�}�����������p}A������Q��xS5�������(e�8*�������a�CA��d`�T� m���P�:k�8G�Kc��&�7d��z��B6e�9t"�7�7ff�R�1��O�D��Y�0�^d�����������,����8��R�!�Vw��������iO���{�)�G>��Ex��)����t1)�������������'�3p�6�CC����<��}���4��G��L��+(p� �^c<�.�s#.B*�8��tq|z|t���W�����XJ$+c���`>���n�/^�hx|xy���tz����;vy����!+�x��c���Jyp��=�sq�/]U���.��	�CJ4���Ff�F�^���yZ���l�������[GD���Sz�3��������D�P0��x�.)@��!V�����O����W�u�P�f��!�"�"�y��:��Hi���Hdy��0z�e&�>6�Pr��X2�>�Dr��;!*���]D����exAW�>�w���|!o����`�}Pq%�A
QMIi�����& �������������'��������� ����"�S������kH�8h��m��6EF�r�������������k�y��3���	�R]��.j����|O�U\9����m��<K�z �!��'Z�2i��s�����|h�B"�tPa` ��!8��p��z������k!g��41�y�����w��h���H1��5�t'������e�db*���p�a`��a]5��jI��������Pc@���J��H$��� �A�����������\�V����h�w���8Y6�t�w��.�'x-xU]yf���xX��z>����������%���K?�[).��R+-�K��d����4�i��BzRQ��;���%9�@Er���V$%f�vS��r������_��J�RQ��d������b��L�$��J�p�`���+�G%�i���J�JL����������O�Ty���['G���b�1��$�-Qcz:$��7���O	��q��[�<�Q�I')8�\H��}����r�0_J���$g��[v��
�
��/%�O+���K�'Q�7Hv�k4��)S) �X��*�c��� F_t��
v�KY������p��l����d��rd���2+�|)>��
%�?&*���A"�.&��46y&ee��	��c��W	�����r�JT���M�'��*=������{T�����xW���m���)���
��%�I��)�������NEb���e��!v�1S}z,�-��Tka5�D��Z���
���������X�����c��,�F����;�<���*�L�!��c�
���R�N��3���|��E�N�� {�9	��X4lX)6������.�J��iA�m��T_;�8$6Y��d�����B��H����9f�;�XPR �xF��5����PA������)�iH�B�K���8�N��������](�n|��!�c�h�B`���qhZ�dfP0��I��Q�oT��4�uX�����(-M�����`>rE`�	�
�����Q�������������z��_V����h��"d�}�4��W��~=��_��|��N�B���,�����/+���|�Q�G(�U�-����$��,A4U�U�d�QDZ��.K�f:���eXZ~A���!GR�(-�1R�qgg���/�5���D-� ��g�L�=���j0�u������Z�=��.�1���d�
��F�|�p�W�|7!xa��V��\�O��B��|����N���\�P�)Q�O�-�Vn�{�x���'�v�����M�J�@�W�����V�g���K�'��E�ro2���+��r�xj*����n��)��a����l&!��[�C�W��&�(J�~J
o�E�%���������>��PX>��zZ5y4��`"@AK5�ST�����i����1��<���S�h��H�9��� �n|^�<�
��~6�\�UMx=�s����w�oiIt�-��F�G��e�/��v�������;�;��&KNL���,�R\Jw��
�������+t��$A,�U\�q�e�,���_��oKvq�3v�B�%��e.�hEQ��S9v���xM����4����H	K�tKB�8�"G'��S������~���������C��"�b\����5sKR���������
�����9zvR.�\q~I*��"d�@B<�U!O	�/W
�_�����[�Ko��&A���	�Q�6p4}0HK�d�����
c+��e������!�|�`�X^z��=|h�z�-�jC�e�e!������]9j�q��}^���KS���wt����,�w�&�����\RN����5?������������xc�]t^���y���ugRe�w+sP��r���[������
h%��1m�`����f���K��{�>��s�y�������om��^�9`�t��B���
���''6�<����Lh�����=�N��)���%M�U�	��1g�-�=�p����[���r�����c<_5d�C�#�gH0�����j ��x�g�dxH�/�R!��6�Bb|+������.�(@���I������s/������_��CD)1=��r��1}-����|1�c��.�9��^A�R
�9e{���!U"�v1�c�Qi�FJ��,6h%�sMZuj�T$��>�=��!����S#4���/�Gb�7�jZH2��FYV�Oux�p��4L5���^|�}<�8%\��d�8�!�^Q����_�J�'����k���.9&ST��S���/b>J�zg���&��W�z��P
K���������4q]`X�>����D{�XT�F�lj��Hd;�:N��2l�������-�Kz���������E�P���#��{�+�����s{c���oE!����L������%d�/:�%���*�)�"�K��rI��H���ZpvN�\^����X���:Lr�����.S��sS_G��#�*�����3}�b��T�7����`����xm����Z`����>�!�����@r�����	�{AM=�\H���P��+���>|�<c�L��	�8����\4�}����!B�������j��/�/Y%xmZ���P���6�}��+���P H���4X��Q��AI"gTJ����3���3D =���M�i��$:r}��	�O-F ���l*v�X�t	�M�'�-9�=����^�cR<\�H�f_}���[�[���X!�a#8W=�����>l��������^�?����f+P���kXi������SS��3��O�"�~~�M]w??}����"�<�������������'�p���#f&�B8��������������G��2�:��"��"T"�5�����:�������h	�8�E��PZ��d�Kk�*���>
VQ(%Q�l��:/p�UFg�;R{�tO=R="�I5��������eb�|���L�ku����j��8���M�&������L����D��zTmQ�CseS~��m�D��d���*(���f��b2���]�~����4�Y�n���3���Y�0�S������j�j�PK��s��GPK�`�P�@( 0006-parallel-backup-documentation.patchUT
=x�^=x�^Cx�^ux��[�R#7���PQ[���6w�C����
��@.[�%w��B���V�8�y������9G}Q�ms`7�K���>::��\$��:d��|ws(vw������w6G����������������Z�K��.�t��u:��	�9`�D�����\�>���>|1���X�=~�x��8`'�l��;C ����N�`���t�;��e:�Yx���x>�:���l���"� r�&�X���KC�7R�F��j5��F��qlD�6��A?���7���co������h#_y"����o���e�c#��y���o���&�*1����Yo4|9�Vk,
�K�.��!�/>���_�����v�����fW�vY�����B9,��\>�_�Vows��������=�&�y:��	��'"#|X'�EH���B��cq����o����@&F����-��	h1�6�0���sO��qx��]������������W��#Q����Y1�l�������-��p5�C��7����ZB'��+�N���?\_��M�,��O����brX|u����F94����rF�� ��T%&N=�0
#�13�E�(��t�"��P�1��H%2�k��t�;�6��#�tT|a���O�kE�J%���F���_E��
�\�L&D��}��}:bJ�d��Hxr$��y�G��K
^/���l���;���&����%����'.5TJ�����C�7�������.�~b$r'�����H�@�7B�oW����_kyZe
o�����Cf�X��k�v�1#9������c�^���*�B�����8��&����T����xTx���df�L�M ��LB�I�i�x�Se�2}n831W�H�1�x�������HX"K����E����O��;�����@4�7����F?2h!c����[��s
`�@\4�d�W����&��#H��!$!���]�f���c(�t<a]��[���D���Y�pd,�I��o]�dXi�2�4D@�/���a����)��sY =��*�Y�Gn#@k��$]dQ��G�P���'@���ta�r�#�w� 
���r�O�{ I���&?������M��r��i���FSK���e�G�C;��t�MG��K9��w
/����I�=��|M���(SV��b�:��d�3��P����<h��+
�Q��f�}<X
�����u�K}���}��c$�L&K���� f��Tl}7e�qp���Xg���B�2��4xD�%\���t1���M rx��	��@�@�@0V((�=����
� ���h ��$L������e��aj]M�o\�6�}&.�,�f'G�!C	���]RB%i�/������\���1���8<��,��?��x��r(tr+�_��oW��P���l��DeV��ea���	I��N�7d� ���H&]��6T��g���D����)��5��?�����U3(��}�J>����Lpvzyu}5xwv|y>8:��'#8����������Qg������g,��
��&�����8�Q���Q�3:�>S�0/��-D��P�������Pk@Xq�1�{�M5S�������B��$3�KP�!�D�JrAyN�A� >��Q����&���d�*�x����;(�b���s���!Fr_+�1X�J�����JC\%�M�0�����*@2�R"U���	��L����xb������	�E�)1���O(�8���\ZY��a�6��.#���I�$�5��8X3��s6��V��g�BY���`�]��=2�-b����E��K��L�D������c��1(�% y��;�)g�a���PRB�4'J�m:r�j����$i����D�&�c;�,���mc�]u���)E�'��J�&icw�Y&�<�������F���_�O�\�G�	3���+V)�JiV��
A����J�m7��a �<�4F��������\�b����s�T���Tf�Q��g.���xC��[�vz[��^w�$7��R7��P�e{{w����Bo�����]'�g�&\e���6�K�yr�+@qw������l�*r����)��f�|\���S]��yS��	�ad�������B�@AQ�Ut�U�����L���!��1����\E�2qC��E;����wBv4mW�h�m�����RHP��Zk&:HM5K�@��y��i�bA����CI��;��bs��"��*(�/����TP��z�L5�\������DfK�i���9�To�q�'(B��+oW��1�_a�7oW�6�Y�v�[��VG��ZP���(����VH\M3��qT�����U|K5XH�Z�4�@�������uY��pT9���CH�6���
�C�D_�m�)[g��1��]�����T%Z�����U`���6��X��K�T���gI���`iEvn�aB��Q~<	YhR���	TV�G�����9����"v�P�~�M��ZP��b�c?�ll�n"0�����S:.r�)9��@P�������Oq��,r�7lD�T�'/Hq|���"<
�T��!6����\���\lg�W��'��#�����k@+������Y���yB�&����8x����)�
�9�����
gj����N�KG��nw*�5�<�$��zx�IMk\{(�R)�����+�������+0jy���:YRy>YR��@�� �b�&z��Lq���nlG�&�E_���&y�[kT���tvF}eO���/���M�qw�c��:I��%����rO���Y�}?8+����K�
����3XTBk-��B��+	���Rc5��<�B� )�u�#��C@���T2��l���Z}q��S�LBVtP�A��~����%�6�i�S����J������,1���_V���H�C���q���ps��U�?k�_ G���X���g���:�1���pt������r�R�$[sh�����R����n�i������^f�M+�E�i��*9����Q��I���"7BWb��:�I��5�g7����^�����3�N@(��������Z�re���nM�r6�Y�?�D�"�U?Tp����<��<w�#�� (��w7D�BN�Vq!�8:Q�sG��@x�����5��g��X'������|�-���%q��������uO^8(#N���;��.����/����-��/q�����4�}��c�L�����_����������.�����K=��l���.R~���b��!��cp��
�C�g�t4��GZ�I��*Od�[�&9�Q�e���d^��lN�3�s���5����3E�eT�f�%��?~�Wy�>�/'y���������z��^qf��0����e]�d�Y�k�����(2@����nH/x7@$s��p0��PS����y���_�DwOE�
�$
���������2pT$�z��f^�����
9r��m�j<�!�H�F������2*�B��{�{]O�������~��q���j��.��Jwzt��v�F��������O�r�&�B���GX/;l�|_��f�M������m�����g"]c�3&{dC���B	���.�e�i�~�<U��f}�~+��o�_��m�%���@�H���nI\	��e����l����6��<p�b�)��@������������c:��tC6]6R�q����U����!�������^�t�4����4<��a��>��swp���X�)�g��2Ow����}��6�@�R�a�g�IA��+�V��n%�������y��w�Z���:�k����v��
"li������7�PK�7+4�@PK�`�Py? 0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
=x�^=x�^Cx�^ux��Y�S�F�Y�+6tBl,K��@�����@_:o�����V�u}�������;��
)t^&[�����g��=%r
;��V�3�t��t-wg[lY�������^�;������R����Ng�����X�#�i���L�����N���I8��e�s��}t3���7���g7Av������u���u:��|����]������G��|O��"���C�%����<��5�$���Y6�7>����X�� ���l���dr#��'��(�]��Z����9
��������M>[|j{��T��z��a$������i� �S��L���l��/"�FZ�Z��Z�q����2EF/�Wc_��?�����n�v`vk�����]:�K��5���������ioA�>-p(��,� ���E�en��	�f�W{��/c1�/��E"����dg�������p&��N�8�kpf ��	N���� �K0K�'�66k���-�����]kUv�g(�w����-������D�n��x�������0�$kQ��w2���}��W�I�^"�)��Z��|b�r��,��!�CIp��8��x��LC��@&p?�0� �����	0����'���6��;����gJa��&�oYp���|2�������ne��x����O��6xsyoe���:���3g)��x$�y�*K���#�V�����=�ex?��:q#6$�+$����''{
�����P�����d�@d�����"�IQM����'�����c�V�~
�H�q>s�7�d��A����N5���2�S�4�m_�.��QkVg��HD�'1�����%o������&��N��Q��lkk��v��e�>��S��ZR�0�	�8L'��P��K�����`�b���w�	2O��������$b�C�X[W>�H�1K�5�M���@,�
2%'�|�W�����3��Ma����T�7��K���2���
cH�8�x����:b�w3�M+6+F��H���|�6��]|5ZR�py��jx�-�z,A�0�*x9�(K$�|��#lI����# w�ww6dJ	s��)��Y��=$�~����iY�X<B�wp�S�E�����hK��-�p*�0&�Q#j1	�@�0!��t��������[����G)z�L1�A�1��GInbW&���8%�j#�Q5�y!���T�	��$�j��M�8���wxqV_G�{z�rxU���������,��"��g�&tL��&�zv�(&)����l.�`)1&�H�?JQ{�5q�>X�B�a`i��������j(�$4��"�7/����*�����������\���l�eJ���ZQb#�$2��a�F��2�
 ����=��v��tMK38l
���Ld�����ko�|����
��l��}�_���M��K�L��	�D)1��J
��M�X[+�ivxNI�t�JA��*c0	��=`�|�	N]�XV�+�qB����L(��D�~�4��;�VE�~��*t��n��m�g6+�roa�������(�|����SM1I�D�>��E���
C� ���y����a�.e�S|+&��2�
�tv*���W�
�]��W�c�6�S�b�a����1��\b2��"ZMF�	N��Xr"b
�s�.��9W�LU��-�UZ�o��o��fkP��[��x����"��w�Mk����pd�K]|F�x��^p0&0�m�GC1��{�E������Z�"{����B��J6j����6'j�
J�][���*�IE��O*F����G*��*�U�6�2�a��d��[MZ�Z9sR�����������'�:>����1f�����WU�����g���;�S����7�=$�X�i�F @@��T`=��9����[b��Ch���	�NW����
����`�p�jmzB�
���{T�!'�[N�c�mJ2a�/�Z���\��gA�1U_�d������{OT���!����������=�|�(r3�s��SBY
�*Y���lWI#������	a�,6�TW�������}�|XN�s�q5�0O�����E����o.%�aj)������9{c��L�"��M*�61����	k�*Y.������E����m�j�m������w�J��RU������$���^{m�Im��,U����+ S���vDc���P�n�N�T�:�wH�<�J3�Wy�i��� 4
S�����1���/����E���6���T�sh�3�h��*���<t1�bW_�(�9I_���?h�5eG�1�����A�qP�u��A�k{��6{t�`[%n�������l��h��)R9Z���u�\�Vo)8�i�B�����&�c�h>y���y~�aUf
c/�}A�i��������s}p�d�EG�r��=�S}�wE5�����ce�B�7f*,z<�'|@�S�C�b����y�&��#�G�%��M3���@������Q������.7�4�d������/�c�V;/�7^��]�.��H���R�(�Y_�R��z:W���Ne�ph��kO'5���P�p�B�%���ma{yl�,�9�:]`�=����Rg���vI��O�'�v���3O=}nZ�}A%�@��oK�X�C��:[Tk�4+�[*����8E������"��U*,�g���`��q�:&��B�7�T������oSMgr��Q�d�
u����x�%�1A6Af��J�������N�K��Y��S����D?�@�V�z�*f2�+-���r�8�4z(���IHWZ�J�UUD�X���]gq���u��=��^���&Z���Y�d����j��*W����\�e�:��\��v�<{�=�1�mD
�c��b���t��G�X��P
!hh��r��\��d�k�u$�K$�H������z�����'�2L4�p|zt|z|54����rHvb�__9g~^9������i,�
b��/��Z�rA���>����2��3�:�'�t��E������g)���=�����[�Tx�?�����~�b3�M
���PbeR����J��
�
�8�vv����W
����O����
%B��$�?������m[P?�����0kYv�Q��PK\r�GyPK�`�P�= 0008-added-windows-platform-support-for-parallel-backup.patchUT
=x�^=x�^Cx�^ux��Yyw�H�}���o,.!	l�=���a�YC����t�@��I��n��oU�@�2�/1juuu���n��Y�u,�hZF�0M�n7;'g�'���dg''F��<m�-��{0fP�@���?PeY���9tC��;6�����@
��������d�����s�,Y
Td��@�Ai�����T�Y�K�+3�s���������@�,f���Y�SW�l?�C�\,� �Bt�e.���\H�P���a8^c1�=d�d����l�e�|���6Tw�F�I��	T�,�f��:��T��Mv}b>����>���@� �}7l��G�����4��kI�yq���'@
�`�to�,����Y9���r
�`1���zY��o�d(�|�j��Kz��8�R��L�bV�WMv����%�c�P�O����7^ 0��7�����yj[���dS�t�-#�����t����}u����*���������
�[�R���e����_<���E3�
%_����w����w�Q�C=��R^M1O7\��6�B�f�3�=����7�����%
�<�d�%f�9�Q�L�<2%=���1u����G"iW�
���Pwc�{a4�	^xc3�A(T_d��t$�Z�k�@��?�=���^������d�K�#qx��d�Z�
���:��=�`�	E���?o��c�v��z�����9�����i��R[�[=mvdI2M�-��qf�M������:-�����A�*ML)��k�3�%��j���4`�f3i�����c[�����n��&����+m���O��M�FM�F�"
��9��,��o	�4���8�����s���^ZN��h�e�6�H�����vM�Q��VMQ;����������!b���pxAV�Q�7 ��`���R-ET0g�7�%lj�K
��JPiu��1!QLChb��(^�p���?|���h��`2����]��\$R�>�
S^����'�����"���#]��9{�����m�� \$��
e�7?��!������9��"�A���#:��Pd	`2Cy�7�rn� )�f���@G&�����ji��%���Hx��8�|F$)9^T*�H�eX�1~�g��u<4��:���L�F8�������R�����h��k�M5T��%7VL�2����W�b!RHQE�������l��v����J+����Pf�e���[k�v��Z�B�sd���#I�T�Y���{lxK���dk{Q\�5J���d�F��W}�j�����J�:k
�t���es$�G
'OX���s�]�Y�3B�N}~
>�P;��n\�@�W�����x�M�/�~p�M��^w2�������W�����JQ��B�����
����b�->������0O-nX�[�N7�DJ�?�������iX��ry��T��i��8O���4a\��J4�[{Y��,���Y��Z��������Dz&�1Y"�����W�\L�{(���J���-�V�����0"9���[�JxfIg�(
h����Xe���DZ"pS���V�IQd���f��,[��!8���bS���0gD�Q�1�F�p*�A�qqN���%.����j�/�f�)���c�D"���4�����;�L���
�y��fh��&g�/3O����FA��<J�y]��'����	y�����HrH�|�/6�c��J�:�7u8W9U���H�M��F�����=J}�c��e���"g�F��9�~y���D�&���hrf^������D���F� ��\���Qc��z�JEU�����s������������"2d��p�L�v������S�?�nl��TV,��Xq0�������DG�=Yo*+�E*4aI�;�����a����1:
��z1��)�YJ��<�1��� k�z>!v�1f0�E�����2�Q���)����R�=L�h�$RL�g�2D�*��a�n"mY����]k�+�]#>xx���ON���J�y9���}N��K�[����!�8�B$A&�>"�v��WX��������:��?���&��?���:�@�v��2]��q}x�����A��,�������bC��X�T��WV~~��4�85m��6vNx�93MS9�U���j���e������W����tT�� �VM=�w>����MK����%��.��R�F�F�a,���Z�����R).�dA�,�rbW������/gu���F���J�ix;��B	�X�nV�����b�f||�d4�)LW ��}��
��k��#G�u�����[�������	���(�NP��Q);m�����O���������a������+W��HN��T��eQ�b�����SkA�yR��SQ�}�m���xBt����w�\�u�����R�^�7���B
�[��.6�VmEz��<��K�
������o6��3UW��Z�$u�����������..+��EA��<m�-%}�)~�����B�4���4����Z��_!]>���%.v�k�������%��v�Pt��Q�Yo�v���>WN3�t�C��cz�,?���L]�8��;1M����M��TImI
��������,�PK����:
�PK�`�P��+�? ��0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
=x�^=x�^Cx�^ux�PK�`�Ph���@? ��K	0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
=x�^=x�^Cx�^ux�PK�`�P�3�)=-�7 ��X0003-Parallel-Backup-Backend-Replication-commands.patchUT
=x�^=x�^Cx�^ux�PK�`�PT����'��( ��I0004-Parallel-Backup-pg_basebackup.patchUT
=x�^=x�^Cx�^ux�PK�`�P��s��G# ��>q0005-parallel-backup-testcase.patchUT
=x�^=x�^Cx�^ux�PK�`�P�7+4�@( ����0006-parallel-backup-documentation.patchUT
=x�^=x�^Cx�^ux�PK�`�P\r�Gy? ��e�0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
=x�^=x�^Cx�^ux�PK�`�P����:
�= ��9�0008-added-windows-platform-support-for-parallel-backup.patchUT
=x�^=x�^Cx�^ux�PK��
#79Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Asif Rehman (#72)
Re: WIP/PoC for parallel backup

On Tue, Apr 7, 2020 at 9:44 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16) and
hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable. The
hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand dynamically,
I think it's
sufficient initial size. max_wal_senders is not used, because it can
be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

Hi Asif

I have verified the bug fixes, one bug is fixed and working now as expected

For the verification of the other bug fixes faced following issues, please
have a look.

1) Following bug fixes mentioned below are generating segmentation fault.

Please note for reference I have added a description only as steps were
given in previous emails of each bug I tried to verify the fix. Backtrace
is also added with each case which points to one bug for both the cases.

a) The backup failed with errors "error: could not connect to server: could
not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.

[edb@localhost bin]$ ./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/
pg_basebackup: warning: backup manifest is disabled in parallel backup mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_9925"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
….
….
pg_basebackup: backup worker (1014) created
pg_basebackup: backup worker (1015) created
pg_basebackup: backup worker (1016) created
pg_basebackup: backup worker (1017) created
pg_basebackup: error: could not connect to server: could not look up local
user ID 1000: Too many open files
Segmentation fault
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.13219.localhost.localdomain.1586349551
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html

This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 13219]
[New LWP 13222]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f2226f76a49 in __run_exit_handlers (status=1,
listp=0x7f22272f86c8 <__exit_funcs>,
run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f2226f76a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x952ca0) at
pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffe3dabc718) at
pg_basebackup.c:2765
(gdb)

b) When executing two backups at the same time, getting FATAL error due to
max_wal_senders and instead of exit Backup got completed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D /home/edb/Desktop/backup1/
pg_basebackup: warning: backup manifest is disabled in parallel backup mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 1/DA000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_17066"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
Segmentation fault (core dumped)
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.17041.localhost.localdomain.1586353696
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html

This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 17041]
[New LWP 17067]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f051edc1a49 in __run_exit_handlers (status=1,
listp=0x7f051f1436c8 <__exit_funcs>,
run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f051edc1a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x1c6dca0) at
pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffdb76a6d68) at
pg_basebackup.c:2765
(gdb)

2) The following bug is not fixed yet

A similar case is when DB Server is shut down while the Parallel Backup is
in progress then the correct error is displayed but then the backup folder
is not cleaned and leaves a corrupt backup.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -j 8
pg_basebackup: warning: backup manifest is disabled in parallel backup mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/A0000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_16235"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_hba.conf pg_logical pg_notify pg_serial
pg_stat pg_subtrans pg_twophase pg_xact postgresql.conf
pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots
pg_stat_tmp pg_tblspc PG_VERSION postgresql.auto.conf
[edb@localhost bin]$
[edb@localhost bin]$

Thanks
Kashif Zeeshan

On Tue, Apr 7, 2020 at 4:03 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error is
displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then the
backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-T /home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup. I think one bug fix will
solve all these cases where clean up is not done when parallel backup is
failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-j 8
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup
patch then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP, not

while the backup is

in progress. So if the backup is a large one, early error detection

would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail quicker.
I don't currently understand the reason for the prohibition so I can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only
intended

to make parallel behave the same as non-parallel here. So, I agree with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding the

shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands. So

that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether that's
possible now or not, it seems unwise to hard-wire that assumption into
the wire protocol.

I was thinking that perhaps the client should generate a unique backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any need
for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared hash
table.
There will be one structure per parallel backup. Since a single
parallel backup
can engage more than one wal sender, so I think max_wal_senders might
be a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines
the maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains the
same
as for non-parallel backup with the exception that multiple threads
will now be
updating it. So in parallel backup, this will represent the overall
bytes that
have been transferred. So the workers would sleep if they have exceeded
the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup
as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this
structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication
command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a
backend process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#80Asif Rehman
asifr.rehman@gmail.com
In reply to: Kashif Zeeshan (#79)
1 attachment(s)
Re: WIP/PoC for parallel backup

On Wed, Apr 8, 2020 at 6:53 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Tue, Apr 7, 2020 at 9:44 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16) and
hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable. The
hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand dynamically,
I think it's
sufficient initial size. max_wal_senders is not used, because it
can be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

Hi Asif

I have verified the bug fixes, one bug is fixed and working now as
expected

For the verification of the other bug fixes faced following issues, please
have a look.

1) Following bug fixes mentioned below are generating segmentation fault.

Please note for reference I have added a description only as steps were
given in previous emails of each bug I tried to verify the fix. Backtrace
is also added with each case which points to one bug for both the cases.

a) The backup failed with errors "error: could not connect to server:
could not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.

[edb@localhost bin]$ ./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/
pg_basebackup: warning: backup manifest is disabled in parallel backup mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_9925"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
….
….
pg_basebackup: backup worker (1014) created
pg_basebackup: backup worker (1015) created
pg_basebackup: backup worker (1016) created
pg_basebackup: backup worker (1017) created
pg_basebackup: error: could not connect to server: could not look up local
user ID 1000: Too many open files
Segmentation fault
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.13219.localhost.localdomain.1586349551
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 13219]
[New LWP 13222]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f2226f76a49 in __run_exit_handlers (status=1,
listp=0x7f22272f86c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f2226f76a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x952ca0) at
pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffe3dabc718) at
pg_basebackup.c:2765
(gdb)

b) When executing two backups at the same time, getting FATAL error due to
max_wal_senders and instead of exit Backup got completed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/
pg_basebackup: warning: backup manifest is disabled in parallel backup mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 1/DA000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_17066"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
Segmentation fault (core dumped)
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.17041.localhost.localdomain.1586353696
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 17041]
[New LWP 17067]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f051edc1a49 in __run_exit_handlers (status=1,
listp=0x7f051f1436c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f051edc1a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x1c6dca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffdb76a6d68) at
pg_basebackup.c:2765
(gdb)

2) The following bug is not fixed yet

A similar case is when DB Server is shut down while the Parallel Backup is
in progress then the correct error is displayed but then the backup folder
is not cleaned and leaves a corrupt backup.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -j 8
pg_basebackup: warning: backup manifest is disabled in parallel backup mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/A0000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_16235"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_hba.conf pg_logical pg_notify pg_serial
pg_stat pg_subtrans pg_twophase pg_xact postgresql.conf
pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots
pg_stat_tmp pg_tblspc PG_VERSION postgresql.auto.conf
[edb@localhost bin]$
[edb@localhost bin]$

Thanks
Kashif Zeeshan

On Tue, Apr 7, 2020 at 4:03 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error is
displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then the
backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-T /home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup. I think one bug fix will
solve all these cases where clean up is not done when parallel backup is
failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-j 8
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup
patch then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP,

not while the backup is

in progress. So if the backup is a large one, early error detection

would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail quicker.
I don't currently understand the reason for the prohibition so I can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only
intended

to make parallel behave the same as non-parallel here. So, I agree with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding the

shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string> OR
(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands. So

that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether that's
possible now or not, it seems unwise to hard-wire that assumption into
the wire protocol.

I was thinking that perhaps the client should generate a unique backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any
need for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared
hash table.
There will be one structure per parallel backup. Since a single
parallel backup
can engage more than one wal sender, so I think max_wal_senders might
be a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines
the maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new
file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains
the same
as for non-parallel backup with the exception that multiple threads
will now be
updating it. So in parallel backup, this will represent the overall
bytes that
have been transferred. So the workers would sleep if they have
exceeded the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup
as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this
structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication
command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a
backend process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

Hi,

rebased and updated to the current master (8128b0c1). v13 is attached.

- Fixes the above reported issues.

- Added progress-reporting support for parallel:
For this, 'backup_streamed' is moved to a shared structure (BackupState) as
pg_atomic_uint64 variable. The worker processes will keep incrementing this
variable.

While files are being transferred from server to client. The main process
remains
in an idle state. So after each increment, the worker process will signal
master to
update the stats in pg_stat_progress_basebackup view.

The 'tablespace_streamed' column is not updated and will remain empty. This
is
because multiple workers may be copying files from different tablespaces.

- Added backup manifest:
The backend workers maintain their own manifest file which contains a list
of files
that are being transferred by the work. Once all backup files are
transferred, the
workers will create a temp file as
('pg_tempdir/temp_file_prefix_backupid.workerid')
to write the content of the manifest file from BufFile. The workers won’t
add the
header, nor the WAL information in their manifest. These two will be added
by the
main process while merging all worker manifest files.

The main process will read these individual files and concatenate them into
a single file
which is then sent back to the client.

The manifest file is created when the following command is received:

BUILD_MANIFEST 'backupid'

This is a new replication command. It is sent when pg_basebackup has copied
all the
$PGDATA files including WAL files.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

parallel_backup_v13.zipapplication/zip; name=parallel_backup_v13.zipDownload
PK���P	? 0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
X��^X��^[��^ux��Yio�H�l��6�-R�ay���W"l&lg�EM�)qL�3�����nR��(�
��"�]]U����yL�6�����;m���l���q:�^�w�k�������p�C0z����?�t���Q�!b��K>�2������Ww<
���NY��#�k�������F���9l@U���v��p+9�O��'o@7���e�l�!v����=@�=D�N����I}+q?���d17�u��
M�������+���=�b4�Yi�Wh��:���}��������LP����[�����0L���Q��GB�R�,�����B��i��8P���Xs#����i�o�{p:f�mv��o4z�~�:�������v������g��_����^�AU|�i�D)�Y�:<NF��|����'(�B_%�6�(���J�(!_FP	Y2��}�5�y���^N��V�J��XM���[gUf"�!�x�-�b��C�s��8?gT����Y�k��l�j.��3�j��Mt�P���(�!]������-\�4�3A��q.���LN?�~2's�<K��|��5^*xD�7BU>Fn����<�`-B'�9.WW�e�#��|�6Sg�6�tu�����\�41{�l+�T�u��5rt��������t%C�1&b�L��o��(�
%��U_��"i���
�3�F����I�Nk�f�C5�AT��U4+@�2GC2��\g���K=@����Rb>������4	��EZe�9�6��e@��8T���))�<+���C�	��'`�
O������$~��F���Q��]�40+I�����x���d�?4T������r,�w=��O�r�$�����z &75I��8�:Y*��bN[��jb1����e
��!B��Z,#WW�:�K�P�z������%���R&��=�z?89����jx�nt:�<;����o
�}x��/��zeH�lVDB*x)�	E��oyc�-���K}�Gy��3�$���
�wCTU�0�V���r`���|?�vxAr���j�q����P�����8voy�gK����y`��/F��[���4�t���RS�?,]�|�\jR0;0Q��#qi�@:hI��q�Hi�s�f :&'IX�0Fh��B�����,%K��L�jW�v2]=�]\%���U��Qf:L-"QTC6��yT�<�(r�����`M����/�����^.�ju�I]��_�ptzY�K&��������F
vU��!p
�������n&���*$v1���c�4�Ns�W�������R�}��Y��I���c�H��cb����)�:=��8>b0��������(D��(I<V@L�=^E����k{���WQy��t�5�M�����<��f8�1ow	l�K�w�N0���<0����>]��	����������U`��Y�Y,�#���J��O���,Oc�@�|��$3�[�F��P������j�rW7��]��)aO�;;�����������V���d JU"8�D"���H����)�p��L{���L�unR�B��$�a��>�.��9�W��|�
��}�Z��sx��h����+���$��8���v���	5����>L�)�!@����A��a�y��0�~�<��'�>�P�x��7n8��2�B�R�w
��
(���������|��^ls	Y���������gQ��Q��=W�����������4�y����sBz��p�$��s�d<��K���rb�9�������['"���D��o��M*y,N�N+�!>�2��/�%_��+�!�_���+,���)Z�z=L��sjQW��A��E�h�X�L/�n����--/�T��MG���Zz�f����(�=jss�a�)67�lT���>���i����'��b*��)=��Ef����-qn�q����e�	:(7�����=Y���T���3w��b~pJO~�c��D���t��xi;��x"|���U���H�l?���������������MG�����m-�����C�-"���\w������Tvd	z���\j������aki�j�Mm�,�@���:s�a���1;���o����{=�n�mc���^��p(�b�C��x�<��H��E������>�����~���~i��djC�������^�}w�g���cE��z��[���j$F��xpuv<8�����7�9�Z��j7(
�����M�F�[���PK����	PK���P�@? 0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
X��^X��^[��^ux��[mw�F��b�=��#0�l�iKl�x�q|���l��#���Vu�M���{g$�a�Y��i���;��yf�o�`�F�c���[����I�>;;�������q�{�r�O�G���|6!kwY�uA��N����1��c6����,������Sw2�M���ze%���e���V�/��.�-�['�Vu8�[�����w���:���g�=��$�X�Y��y���,	�����b�"1������c��O��
mf37a���,y�x�����Kx�y0��X#O��e��Y��=�<s��+�%�r�Hx0�U�X�4�����Y�;4����	�pb��%��?�Q�!U��z^,��l��}��r��+��B�
0D,V����ZE�Z �P=�g����L��Z�;4�*�#��
�9�q|�D�[��?�`���|e��#�����S��sm2�!*-u9_Y������{sG���S��|��;�W��2���n������!j�n���O�'�z����1k4&�D�O�~�t���;��n��N���>>k6�g��s�}��n�N������X�l4��?�F�u�>70���SO�=�f��4T��#����`� ����`��L�����b�9�\34��r����?�f0�00/o����w��QL��<�h�$����^���"�o5��l��.��� �O����W*� ������!��]�
��b����T���
,�A2���v������U@�G6�C����dV*�J,hZ��>��J�ov�������[�.?��=e#Q(d�N���t40������k�,��g��
���iU*��5�������
I�Wlf}�F�?�[���h����
p��+7�f��]"�D�����&�����O�0I�@zQ9*v�+To��A�CEX3l��!mi���a�cL��GV��Fj��3"�y�1��{V�	<I�0
&�9�P������������7���]����y�>�����63�������������O���]����k�!My����!�y
�|=� �
X��XE�����?L�j5b ,[e�
�w����b�on���O�UA{V*�����������[����������s�/�6�k�_�����A�K��G��r�Ed��8� -9�+z	�~q��Ba���q2�|/MFa�B�F�G����4����+�b_�����d� ����"4�CP9�R+��A�������x�`�o��@;G��7����?���������G�J�|��=�H5�d`*����Z%�#}P���,!����J�vED��O�����[C>�Tj"�f���gs�!����q6
�����������.�����g�<�tx����/�- ��\�_-+����4�@�&"A�����������a	�k��H�@��9%F�V((1�4�m?-)�xy5���G�4HE��2�
��qcL�s7���<���	�:�h`�"1`
����W��Z�PDRTL�9�fE��
���F�M�H��&Z�y��n=���Gqa5q�k�hL]>�����0?���
���0�|�K�sah�����b����/��@��i�!�*�F��`Y����� �yLE<La��d?f2o;P����U��g0 F� 1�f�W@���H,X?��P�_����1��sU5�X��b��zh3��������UtV����J�����Z�V����"�KC1q?���a�\��Z5v�F[�&*���T�T���N�I�]hu
�����JF1}�I|�>�[K�Jm����Pq����jZyWV<�+>�RzmM����Z��Z!T��|3H�����2W&$GB�4�w�rK�p-]=�G������P���-0�x��Q���,	�B4M��7��	+�i�`8���w��5fM���R�����;���0))X7�����\~���o��{$=����������U=m��2S�n d���8v���Mj�=YZ���r�(�J��{�A��gi7�Vt��"k~i����t��2Q(�=k$�6������S��sr|4���/7�d �'��R(@�����W�D��9AI#�fP��*�r���-�o�V9U��,t�#%����+���GOV��'tYEH�*>�W�Q^�F�p3l�����^����	���"�������~^��������8�F|>�1[!~�;��Kx�W�/�B�+��� ���0������n������+o�����
�+A���E\�m��W�z%&�\�M��'�h�>[��p=����P�\��B>��Wbv@�:��l����p<���mP<Yr#����|S��F�|
��;�w��U����;�x&x'���K�^��g"w�l�.�T����X]6�����+���D�D���.���6j������S�L�	���l�ON�F��qwT~�T*p�����������5���N98�p���z7����{�w���k3����7�j(�`�%�
�0��-t}��J<��hCx��T{j���+�Rk�D� �SBvp5UWI'�\k���O�������b&�[X:��|����~��)b���\�%{���j
D<�]y�[�z�����`:	 r��-��X���F���e��G#��s���>a���5�t��JH�z��H���
�\�k�K��PLn���=h�F{�K��XG=f��"��~�0�'E�ca���\��<H3���r#�?&������o������U�:#�k�>�d|h���(_�
���x�I�����A�v��?0!)�\����"X@@��t�0�L�	h��5f����,FD,
oG@YP2���1�{Gx C��ih�SY��A�o(I��X����)%�!d( d*L�T�3�sP%�n��!`�`k:�r����w?Q-@y%�
O,"���������.Lx$�������nq���:KJ�
Q��@e��R!HXc�	�#"R7I`����\9�:��5��CA�q@�������WZL�85i���K�H-��n����� ��]$~G%T�ei@o��
����K�C���/�z��k��B�V��+c� � ����|JiaH�DMt��I?����`�~P��@f�tM�[�y���������0���Sc��n%6�bU�	�xf�l��:��y���E{�]����o�T�����Kz&|-���OuG+�X4�
�$���R��1tSb�>��9+����%�ZO�jzX]~I����!�t�S���}�-(:���5e��Rp9�������6��@�	��&��X��N8�,��~��f�Qn+���NJ����g���1�����2K���8���<A-�1�W�^)e����m��h�$��2N �� �id�A��4��W�B��^8��X����.�x9SV���Cqi '���.��A�S^�`N�,e}���\��9#��&VH^��o�^@:��B�&/���d��ky���c�
{��`/��t����Ps_��B������Rf�vmu��\��v+������S#�ev�)�`8X����d��l��(�	�YnuZr����=�"i�W,G�Z_�����K���ol�����i���|��4���b���}�����Y��e�T������z��X�L��r)�w�L��^l��i�ma���9Ysf�9.`�e���4��XA�	(|�b`���(����
;�GX)�D�e
J�d��1����d�]�9=k�Nk"���@o�CF���[JOD��t�bX���J��T9R[6��������n��Q�o!�B�x7/��|%��k�3_O��Z��hs�	�"i�K��Ni���6]0)��Uc�R�n��H\����k��JA���e�*%m�]�X+W��;qV��(+����oAX�b�:�ZrS�����$�|�����k:�`��I��<5=4����mHj�Du9c^�;��<mH_�\�'�t����2W��RT���q�m�U{.iUtU
���.�U)����s����S�twdEz�����qU���:����V��<�oDS��%I�rT^NQw�J	*���Oy)o�r��$�2o��h}�S�/����r��R�)��zJJ���Hy9!��D��^�FtT+%\���%Lt��w$��v�
��>P$�y��>KG�����,��,E�������e�!�,��5���!��PE������	���!/;dE�����|�`�����������p:���=j6O�'����>��-�X-%�2��=R���3����7������p��FRf�H]c�7gH����=u�M?�,�5 �t�c@$�j0:@�����?P�k't�j>��9AG�{}����-.'/(��(�OA�4L�$@!#ym;�<�5���,�	�2i'�U��Y�V�4;��6����������z��?PKN�$L��@PK���P��7 0003-Parallel-Backup-Backend-Replication-commands.patchUT
X��^X��^[��^ux��}�w�H����_Q����x�
=�` �!������b����H2!������6m��0o����@bK���u���*f��s���V���7>:��;�\��c��y������i5���m0}w!Z��|J�D��l�_A3O�q�M��;�9s��_!}�����^����������PM��_�d��n����N�i�-���f��_^���O����'oD���j~����}�?;������w>�^�7rbF8
f��8*�S/����+�����x�k��q ��+�d�V�rt����E���g��^���[t�d��T����B
w���������G�|��V�F�\�����r0�����_���������}���_l��:��������AO����r��'��Eq��� r�/n���vc���8�;���b���gF#��K��������;=��������z�:�H�'�������!N�r��C��;�$��`	'��,�<��^�����Ko����8vF��r.�`�F����i�����)�&���	o��co����[�)���?�>����������/{�������s@��h��s������Y}�:=��MW�n�A���N�t�}q�V�5�_�Zl`�)��;[��������m��x��b���5HhQ����o\p��X�����(�������������.O_}��������-.�iA�b>��2G��=t��t��m���zYD�hW���3B���Cg9���~p�	��'���j��E:v�r���ak_Ts2�����u����q{�+T�5���D'l�4�QM��� t��]o1���������#9vw��E#j�>5��.���/�T��G�;�x0�:�kw\GGMD"7$�Twj����������S.���D���^,���kv��L��������G�V�5q����k������h5���."�&=�ay6��/�V��l�`y�x8����s����V��1��60���L8��NY�E	�o��y���	�@d�i����r��������Z�^��������E-#A��p�tq�(��~���T�0@��D@���xkgg�Y�z��o���@����~��`�[<�i\�5�E|���>a������G����-�Z9Cr�����&�1����8��-F3g�XXC��^�������XE����o��ic������d�~�I��Ov�Sq�����y��B:��"���
���e�
l��x�3����ck�j��p�K�dm�B8�;%\0X�Y,��J��p(�����j�br;6'{����������N�]��?no���;��(�W�Sk�D� n���$Y[�n�.H9qc�e�\���^-=�������{��E5�b���C�K��~4�mp
Q�Y�w�8��-x7�#�^���3[��r5v'(��x6���qx�;/�:���7��7������ZM�*���%�;���7�����m�������W=�7.�
N/��{����~
x�A�v��\5���]��� ��q������;(@e�9Z����T�1��g���;z�%�n��I!%��z	�-,��6�2a0N.���2cABA@88����zxX���50`�|=���O���_�5��
�7����'=��R�a\�������<�&u�W�������{�DU��c��R���P���'b��.r�g��"�<Z_)���,���,�����Nd�e����u�+�#p�{����Bw�\yK��O�>U.%���a5��,�;�������������n �`�*�x���}�
�u��CY�x,�$�#����V�G��
��y�[P�i���j�
��wa=�9�o8�]����$�Q�LOu�H���M7C�k�A?����H���xz�xre^�q��3���%��j���g���Y�\��+ ����P<a����.���sPx`��8�
�sb��#X.H04*f���H�M��>O������Z�q�@t�J5UG
,H�PUBYC�[��Wb��Xa���d���������*��9����b|��o,�W44q�h���b��k�:m&[4�/PFY%��XJ���E�>X``)Y���4����B�������&SB�,a
�+��[�Y�<L'���&eK���C����vs}�_
����~l��������Ku����6��'n��do���SD9�;N���
��	��`��F��N����EQ����������<�J�\��
�h{�3 ���En����0�%�Z.�X&�O��
SP-Y�����	�m��rF�N<�{
[+������*�3@+'��ia���+UG*{�WAZ�P��R�7�]j�m����y*��%��X��b����R�7�3�`��z%E�k	F�Qz2�V����J^�/�#n����s�KET�����b�"���osM��A���'@8�@4��6���U7O��XeWw�&:C)��F/.]
A]��Q�pg����:���H�=�u����H��(%\����j�CQm��X{��7��g/_�Nr��ocRn���n��h
��V��e����,\�1,��XrU�O��`���rO��V��Q�EJ@�pz�8�8��2��)'����b2�*`ah�*VS�TT�[M	�u��:�>J������a���U4H��/��*N��@���~����9��F(�m�f5�N������fR���2v�D�<�����"q��?
�B��l��S�nFt}a��3w�����sT.�cHqz
�Oa�h3��|���|����3i�G�0��f�;��T�z}�hQ0�Xb;��A������|�w1��!�y��$&����$����c8��J(�*�~	�S�{9�b��Q���@���QnA��P6%5�A/P�ys��c|YM
���P�����J;�|�D*O�5U�'+�p�I�4'(����+[�G�g�"�,�~2�x��<��#*�;�������V�BeI(�co/Z��,�;�1��������-q��.�7�����3�P�9m��IA�����7���bh!�,����K���h�W�cK�k,��P�����VQ���������/�?�{�05q:�{h|�R.�%���nm��v�-�w�%`�ReF�C�P9�-���F�q)?���)����=���HV Y�9����#�D�u���YK��B��B(�jR�@D��E3�5|��g���(,4Do;;3�]��Pc��*�;��<a�T���8)��H� M>��R��K���4�z���mN���)���RP�=gl�j����?��"���6��i�j:D����NLO�U�r�m4Yh*�`f�H���$��C�#����V[���h)�L������5�a����3���j��A�$��������uX�tEu����:�Y�o���E�+����-�$��J��c�Qh��+*loS'
��M���!?�%�	i��iL8��f��(��s7�	���L^�h����8`(��V�0L���IH�cZF�.���;�$��h���lw������N�__]�������G��K8�#�j��R8xG���vU�����h~���h�k�w���]���Q���d>3��j;�91��Uqf� ���m3RD@,nDE�8z���9H���t�R��F_��	[z��S!�8_�;P/t����4h���X���,�Xf-�ldi�&,C�����n��8�8�i�%(����}r��u�'��}C�{���Cu*&,i�������u��	���(��N�kSK��R���IS��H�����*��R�����M��!]s_���F��:6�a�g���hO#pp
��LN|����A�<\^p��{t
���#���>j#����&�/�`dY�+3m��vK&�AEjX��i�����/*5L�N'��*!�Y�@}�������o��#Z�����>A4�{A����*Ytpy|��f���
���d�\d]/��J'�x���T7j'��W4���s
�
���F���4�d�#9��;@�a��$k����)�
D��[�m���dA����2�J��X8�'�(���,��
�)w2�!��&����\�*gh��!h��okC�������l�}��NGO�9j���Vw��R Y�.���.��&�+�)�+a	�f$P��*rn[��pPJ�z������(��v���N��?�
�������L��U�('�G Z�����0�N���z-������Xw7��!��Ah�d�vr�}�I����av��/{����b���]��'/{�������!�������/9>�2z�o[���m�(��0�`r0`�F�9�����0�%EH��83��x(m��n��c
7�\.��U7]6t�}�E�DaYK�|��^���^�\��9��,��T�v��P��d���lJ�!������N�Q"���V&� �c ��4��@g�[R�JLRT�YDQ�@��C��,7r��V����X<���
YDx�H���>�!3�};�v�%+���k����x�%�
v�>g*�#�0����W�\�{"���vU[lY���g
����~����Pz������+ ���_����� �g~���.+.GG�a�j�:��t��"��h�;���x �E���'����/M ��!d,�=%��lh ��A���sdO
X_1}��+g�8�4@����,���:��TG�sX�c��@(�������h�������ZY3j}���QC�+[g��f"���]��rr�Y�
��;�(e��GK��6*���&OIXq�<���i;�X-3�;����8��6�6�q�  p������Kp�r����X7�����bU��)�n���;Z{�Z�(91���S5V�����1xU�@c
(��W�}	TE��{�����*b�k,����3����%�(����!
�DE�w��\��}�
��D�/�pS��V)*����H�W��o{g��O�#`��s���[_���\)��)�u{�5E7/�hz����
U���������;�������q�0�`W�Z�+^��������([��U�m����>1i�7�km�'��V"o���'����o���JS
��c����
��&��-0������x$UL78�}\�����*�X�(M�h`��(��B��c��U�����a�6a�h��]/����b#Y�V�����������@���&��2�m�yG	�Bl=����(>6�#*��~�B�g�)<������lc��6������*���MF�/��&!�KI���	y������]�T��ygw"k�sDD�N
���x��9-/�r�(
�NT��$��;WU�.c�EqypH2�����wA���5�.�1r]m�=���>t2���m&&��$��n�e����LA��#g.�@�F�Nm����wC����������X
 5IE��G)`�A��b#��o9�nU ?G��1�jIG��|��4<Oy�����'�� �wc��isa�81�z��u��=�R���h�_�8V�����s��zzj����!~}����9�\1�Mm0�B33���y���8������y>d^��eO��(T������
%�j���
os&�I
p���lG���PUF�A���:Pa��C���^)�$�G��J+eV��t<Q��$8�����<S]��{%����n��i6�*VN7h��\���a�.�K��Pwue}E�.�K.����u+�Y����,Zl��A�g)�h���������E���J���cP��Snx0Y��d}4q��J��y�M�:p^J�3'S�UC�+��Vj�e$Q�@�<���2�(���	W��
�T�|:���w����y/=��1�Gb���W$�v�1��^���Q�-i�z��bP0[Y�b=2��������:����������]�q��|`^X��a;$����J��V���0w�`�4�5���ZJ@3'���H�DI��I&�6�(�X�!P����R����~�]��q���v���G��W�D:@�����:f����2$��h��&rU}q���Q0Z����I$:]S���g*FV���J�V���cC�r]%��o6��@u��x�
���{v�9����=�~�����B��}D8���P��\u��L� �g��ETI�'@	�T5�������nN
�7��F*Xu R�����jDdu���rRY����w���E�:������UU������SV��d/~�+�f`���e�nO������p;:A�r��Pn�M(bv���a�D������:�;D�h��>2���-f)��������x���<�������'����P��u�e��__������$}��!@��)���j��x8y.�4�$:A���a��������>&^��./0��R�J��R~A��\@���b�R�a��Z(�u�R�a��N���(^�viQ������
���������w�p4���2�V!��3����M��j�����4�y�T�q0����e��2s���$����+���f�_���GI���|u��>4�����������9����,C�&�����kM��(���";0r����4�%�Ta����h�=HG*�������2�"`7H)���6/�>�����uE��-<�@Ey�{CU�����Aa��N�]e��D'���+�k�
L���N
�V������������4 (�X,G�����i��
#�d�Mhe�*U�&�KH ��!%�������f���^^������
���P
�LZ�<L��%"d<:D���n�g���/��	�u�1yN��h�"�� ��o�IZs&���@��\�����n��XX!.k��Ozq���OZ{�����2L:��i��������"�!���{8}���"o>��u��n��7qLZ�[7n�"|�w�;h�4:wo*��n/|�������������y�[M�����R�(Y8j/V�H��MH��y���(�����Y���2:(1����1z��ca��-�Vl��j����w�WkS�qN.��M��'o:��=��#G+qm���E���)V}nF�lU����!$R;�J���,}>Q>��cYS9J�[<������u�����Z��	&�G��7�DYb�|4�G�`�1Lt�����c�?�dd�*`N��.��n���)��E~��B����--|lG4�+L��b����2@�\��D>��I�����Q��������L
�
�K�p�x����8-�
��������:�D���C7�gW,�8�j����gnnR)	k]W���Z���H��W9@1��a�����+u0��%�:��$1��$-q�S��[cekP����N�3���S�x
���b��9���4��PWvp���a�'��d�9�8�#|����E�FCx�I� i}��k���8����&g<z��Rl���ao�Q:,��N����*�DCi�z���������OOa}����oV���^;1���!Z��A���
oCOO�K`��xF9�r��XV�)�s����#[�u[�9h�����S����/>}

Q\ Yr��(f��d7_��#�����b��C�~D
R��xN�eD�T�}��2�|%b��Yn�R^jOR�0!�C�e�@yLe�HU�0
�t����&��fs`TK2���3`T�S�p�l"�����V�F��y42�oD6�oU���X3{���[�tB�s�WC��A{�����|�l��RN������M3c�7<JKIC���@����Pt3����J�$�D�������5a����Q�.yzA��Jy�~�l�LL(nIg��`L���o)�����,�{|�f�	z>X���j%#�����H6v��a�����	����
���J&��������j��	��s�tBq���h�����������5��fH
Gx�N�����tm,g&=,�``�G)4�����a����d�P�c����mfi�`��j}:P7*�`�xAS2�esS��0@�e��)S6H+�����Etl�
��/c-��'�^���E&���-7��=&{����7v�HK.d�vr�$w8h����ID��J�!�7�n����g�9�#���8���2���=�����/�>B$t���wM�e��X/�uT��S"C&���4��4�f��h��h����4��87��dAQt���8�3�����C�m����>yO�
�U��D�.��S��t��4�4�|�� �kj������9���D��/���r� `����u!R��v�Vb"�[�{}�{��t��c��������zD��N��'����(�9�S��,���@������.����T>>�@��-y��&��/���>c�0�t!4��j��Rfw��+?�.������w�*��AVl6�*�)��2'�O�{���hm$�*����`���9k���.��(R������F��S���x�	H��K]W�	X�OqV�H��=��F��w?["gh�I������]�yV7��Y�sc&�@>�tZ��p�{�6��Y���"��M�z�A8>���jp�|q<�����Csi��70�i���4J�=5����>'�M�N���j^2W��B�n�U
�X:�L$*����E)��[�vn�:�^�W�KJ�O+R��_�&:�X����W��d�y�D0V;f
�/�''���0�%�]QM�G��gR1Vi`V�����2O�=����i ��m$�H�z�Q6�t��T9-�Z;��>�`F����@b{���r��������4(�vh��\��c��N�����~Q�w�������T|f'��4�����w�p]����U�Y���GF))��$,L�R���W��S7��#���K6q���Hf�A���y���Rl�.��dwY:`��,.�P��_/���l��&)����\�B^>�|������Luy5�i@���N.�}������=�	������(�!��U�n����_�
2+�`��������O��{�X(���	7i�4JX��r�P���U'l��q7lQU��8�c(�Z&?�v��L��?��j@�/Sk�=��O��-�[�\�0D
�R{�r	�@6e55��"[�J�-�8���(��%���"`��y���iI��V��X�	(R���J��y���7��QL����)���>Ev�MA1w��dc�?$�+��N�$�ledM�F���� �P�����z���W�^�����.����#?y�imA�
����2��(jt,6��
o�U����r���n����-�c�u��]	Bm����pon7�U0��-~���c��m��F����l����(�����{a����E�|���M������h��/*���{z_��� j��<���?�f��3�=�w�t��jX}�5�8��6p���=��62�����
��!���Xs�`�7�bh3����%��@�C��$�K`������l��K�d����r.��
U�"�Y���d�������|7KL�_ ������[<2�EQ'���e�� �/e���NFw��
d��jH<�
�*���Q����0��p�}��q�E��o����K�I�'2}�!Fj�!3��8�����
s[{�����i��x�����)(U%�PM�r
Ho��X��������N��^f��Q�\��e�8���>�%P�x�
p�a|���A�gX������(�	���z;WJ[q%#K`$�i?_����^���L��(���*�)Z&���n?��	��rM���/&�)�[�>n{��|.�M�dz�e�z<V5�\����Ka�o�pI\r�K��%��}[q�O5�w��+"u���-n���^��SV��aR.��H^�^2��un�SN��\�[����e�@���+w��;wC
]r��5�p���/��
�s�2Xk_F�����L&��I_o0S�k��#ya����W�\-��T������Nk_{�?���[��j��7U�P�)w���L�dh��oA\��*�<g��\�����g��9"��b0�l��^������w�z��d=������90��^�9s4�l���XWw.�3�E�1l!}�+�����M�j���	�S������zF��V{�������;�Q8��le�J�J����3k���MJ�)�FL�:Ns��[���A��pt8�4�}�j6���r�^���r�Z��g�����a���}qh���(1zS��?��L_�+������&}~����b`=V��s
���~��_������4��W�F�nF%�M4�S����L��+�.�A="��#�y^�dN��S+U�x����?������B�B���#��8��R�F�����rQ��M7l+V���"1O��Gt�.B����8k�Hz�O����FD+�64U�K'����Z}�]L����z^�y������[/0�.��n�+;�3�T���(�(��<MQ���*�^�<+�cY<�+��S�r��D$����y
�23��`�����L&���61��a���$�_���<-����J�?����[����J>1��GQ���n����,(���\�V&s������3��#-���O�wu�||u����������DM��}xy<��Gcx�������<}��P0]�I�x}2�L1|�%QA>�J;�y�d+������L�%s^���=�\��8M�Mu/���(g$���b���'d��/�M6�TM��
6��7������:�}/o�O�u.�K�����Jx&$m���b����w���X���^(Q<�*�����90T>�v-���,C� �@�L1�|�����Au4`\������"�2[��A V�6�?c\�@Y7��!(t� )�H��u��i*��?�;���������=��B��xm/�*��q�x�L�-	H�$.���,{&������0c�(���O�[��+�m���e��4H���985����.W�m���)����!�[��P��@��6a�y' ����a������)U @���� ��Gb���]�zZ��R��bo�
L	��+0�^���'����m�V5��k��4{����FH������L�Co�@o�����.��t��������5�����-��-_�U>���-��X��e�%[���l�������KIM�{����Cn]S���+��x])���)E����X�_�!#���d�"S��%W����Ul���h�n�~x�	.�GV
���6�( �E���c�E�c���y�{��dX������Y����l��D~#Z@��sjW��D?Q��Ws�dq��������������)�^���YJ�v���1�S����]3��	�
�[�K�)�Wm^(��2,�v�/`e�Ez�}����?i]xH_�%���E=�F�����q_Z/.�Nk��Q�d�2�;�m){+{_�:������U�qF1z��y3*p��&�����L?�:����u����wpJhI!O�]7��P�dXf�qD��K��b�&vw�X�;~RD=w��D�k��L�)N.{x�e�����1]��?��=��������7���L1�]��C�a��E��gF����%���-96��(��;�)��
�:/�.(]����3>�����F����w�n���.r��^rSX^d*oNF�9<����e�C�-N�*$��8u|D��'_���"f�5o�+���D�	�2�4���,��.f�3Em3!�@��S�jS�,��^�z�5f ,m���fm}�S�l��k�]��7[�R����B<G��s��z����~e(�n\5�{G���h\� t���8��b��i*��9�(7��?��se�'����xF9�v��1��
���Qc�U\S��%�G,S5e�g����H
�Y������K�w��W@�����������S��\��C�D�1^�~��(��DI]L��������~�.���3�P�"3c�����G}�3?��|�l�p��,�������}���F���bxX�gF��0tn����=&�R���}�fuS�@Q�
�x ����z�b2�����)v1�'"zO�S��
��M����ou[��s�ht��fk���u���-n����2������\����v��]������/�'�lv��)��������[�4i����%s�\��W�YG)�f�=M��3"���&���b��&�����~K��g��e����kJT��s�c� u�9���F0�ujG6e�q���yeQN�nK%�W��$��r��<@�f]Ejr8�$��N�3+�7��_�hf
���I��rF�v��m5����s�w�u������,�E���"���EH����`q�"3�XPy��[%k�gb �p����"�_����������D�~.�/����f������M�:����l
��a�o(��.��F��h���3���z���S.�PK���;1��PK���P�( 0004-Parallel-Backup-pg_basebackup.patchUT
X��^X��^[��^ux��=�[�F�?����;��6�8%[BH�.
d����?��AA��������<fF3z�&�����# ����3g�[o�p"����`k���m�76�;�nolt��Nw�����pkS�q�NEgG��=�Wt��N�-���7����	�������������5t^U�8������#�
-��n[tv{[��nG�������l��&=�����������i�&����}�����l*�bz�8�;�������w'n��"�vE�N}o�$�='�(�h���P��#�e5��w"�1��E<�N�(�0���p��|x�#X��$�s�
G�g�_�O��{{������8� �U��qK\4�����N�z�o��0�:���D�c1�|7c�2�=v��nO#x����@�����j��w����{'��������?�4
��b>��Y���!�1�bo��NT4n��6���������-T��������v�Z��C����\���oo���F�Om��;/���]~��W�#o<�-��`���A2X�]�F����bw������F���p��5�v{{sQ���UX������hv6�b
��#~��*��;/���+V�a�\En����x���}?M�#���_=��@C��#/���y��'=F0v���mC$wSw��E�D�a">S���.��[ i F��H<�8Sh�O~<��Nr�ZL�����T*�Y���}7���	��x��L����yY]����]���.���B��������9�<���h-/vp-/^4�;��y���	��'rA������sj,�9���U5MRC�}070�@��e����#Xk ����uT�~���p�
"����?��~��o/�����6�B��xB��� Ib"�����s�4�%���1p�k/�c8p�0�&���u�:�<p�����i&� 7�M�;F&���u��!�����q������}��ya=��o�����g����p&��/����g����)��&�J���0��t���L&�O������f��d�xH��.}��+8SQ����o�c�|�C�<r��I���4�	��������~��K��ic��GC}	#�WK�Ta�W*�>������[��+_D��+B�Gji���R@�<H:�N����$zKx���;�Li�����0�8
H��!��8�p|-�����[�[�w(� �p��pY��0v��5^��w}i����������B�c2K�/�M�7���]�x~�����������������������G�9�(�s
>��;*�����9o�3�>8=y��Z�?��QBZ�N������	����[�G��#F;��i@QO�S�������?�5�����K���O,������-�$�6��w;��d�rAHJ�3X���
�@��K�`�w��x���c:��nZ�%My����H�����j:/���wp� (��]�"�Uq�x�����>�

�lA,�n������|h	O���N�	w
L��t�e�z6���!
�w@c�/!9Z���@�,v���X������Q����;�&w�0������#�D�h0:��������v*�d��x
)R���=���)�<�z�|R�~vh���w��I�+E�Yb"aC�]`j � ��1�bN�0(!B�W����,�Q@�?��7J�����?�%�F�`��`����g���V�X=��U��\%W�$|(��������f6����nd����]��� ���|^��gIz����A�s�+P*���mhpL��r���
��f6��]��9}��`d�r�����C|��,��nf5�#�W�l_��Z������u7nBS-�s��N=�|��Xm�$����#:��xZ9�\n��
��
�Zl� �'�����q��)���	����$��f�>$f�D|��}��?�1G�����7i���)I���')b�|�|�dx���w8v75�w�.T�hE��/C���@Jj�"��	5�C�����5�aFh
�/af��E����fcy��N�#/��L+�l2�N�G������:r����^���5��{o����m��`��!+���5H�n0Ghc�������d��+�:"@�������M��	lwx�&������w�����vcd��N���������'�'�0�"�@fh�����Dx5���H��,����]��4j�.�b;����W��x��S@�oyD|�`snl� ���(�)��z���p��7`�����s<Riw������q�w�0w7v/6q�K�����*5�5�r0�G���4T��t�.qK��Ahg�t���-�-�0�3i��I[+h[{�i��`�
 '�
��MfCP�]��Qs��=��N��4H;?qQ�Q���>�x�u��T�&�.�yY�fM Q91�G�h}��_6��e���e�}NZ���V���k<A�TP��9Gn2�nMA��~5b+/e/z�'|�����g��Z��8>�G��/Y�2�i�`{��UH@h�I�E�JQ�����jw���i��7�W]�D���Z�F�t��5��[T���}*�����<��J�����n\zI��P�Dj��,.@����Oau rRt^��Z�oD���;!kE���u�P?R0�?��=��d���tfx6�d&d=��A��k��pxT,�A1�8����RM�*Z�|]����+��h��DD!����v�m���(�go���'D�8q�Ys���S�I��&����2��N9]O�I�r������d��v�'�+a���o�:�N.�7�oO���_
������|;<zS��
�L����8S�k�C� ��^��3��T�:��,��������=!\7�	(�����O/�>{�������Qlli~!Y5�%r(�!Z"�f��
"�$�R���L�M���
��m\0{M����P��_��o��Z���������x�i,n^������u����+u%r2��<Y�&E�f�X6��@�Z��5��++�g���\3���.�`���'j2�L8>%���=
���=��6�������#�3d������V����Y�*@?��H@�En�����^=�c#���M�]J�>�8��K5�&v`D���Y���9	a���������%4K�[#�L�����'	��myJ����,K�&�{�J��I�;^e(���E����!Rg(� �(�*�v��**\�|�]�����g'�HG-�GIv������b��Z�c6��Z&����&��b�-�P���0��ps�b��:@P�\G��Mr�u����xI�{���#�U��!�(���5��y�KX�`�G}�
&�]�����!��s���p�2��
~�����q�������>��N���������o��	��;����m��*(d���4���i�<���)��c��&%������������6�]I��q}�k��b���c���I�Y�����R4g-���|�BFc�0*�>ku���m
���l1i~�����L��uy&i�k{b��%�J`7_�����te��H	8r�<u�>+�g�_:�����������E=tv7w����>������b<I�H�F���!����0+�������,n�vF�7�a�ry�%��
�1�'�b}14i���6o��
i�{
g��aW7�����C}y-Ay	l���7�C�&��^�9Y��qap�0���f��U�x�`8(B�o���&�T��C�A����`v6yq�$��%��2=if��bJ�@�H�r�~�B��4~���z	0�##�O��P���T���K�DW�`��YIe>�
1���I�o6C�I���-M4����n6�x{���.?�-�dUO�����:f�ri+�����^�[�j]ii�2�L�S����W}�����"m��������NX�~��(��%j��A�~:�k���������Tz5n��3�	��@�t��"FG������og���k���f������$Ju�s!���������}��9`I��><�O�Ubu����&!�:W�C6��
	4����w��J��V����{{B�Ua��n;U���U�M��_\���T
F�NN?�]�������kn6�����*x������l����~��B�����t������xx����/`��/'�?V����2=���%�e:���L��}�O�o�l��N�����p���^�<`������l�����d�;��h���p�&_\��_����
]
���S�,�W����O3��
9��#����~gF��+C����R6��.�$�`xP�>;����*��}M�1��!]��VH?�P�_7��=1��j����<<��Od
����{wr�&5�^�����<����b���Q�����v���u���R���5�y�F����n5�d��x:[Q�)��_a�c2�	*Z�xK�X��p�[�&��&u�3���7r,���ES���Y�����n��w< �����]j��")���2���]|�|�m��������TR��aVQ��#��"�d��g?��A�FW3�Ur��Y�utEzl1�������V��U�Fr�V���Y[��8���w������+=����������E���L"��<��I7-i*����3X�2$1�x�x��J���~�i���6���<������GO����YP�$�}�a(MQ�������|��Rx�{�L���`C�Jxkk���gy��d���E��T2q�Lkl
BC�t-s��\�{�)d��a8�L��]�e��$��pp}�6P�&�%34�P�v���UdM�JoL�����Q8���������e&�P�1<�:~O�rr��PY�,�&m���
�[3�n�&�X+n��Y'sQ�T����!�ht����1����!�L'������C��A�$��a�A�ki2#�����}F Z��hD4�1�)��wM	U���t-Y]	��O�����~i*F��$+��mo���Zm�6�8��X>m���R�a<q9X~p���[��L��{kct����V<������IJ��#W��o:t<��Sg�D�������thK�r�\X�JI����D����W��Z%s-*It�
����TJh>HJPGu�����q�8�����3�*��f����`*hM���vJ@������R�V
�E��pz�j8�Q�^��4�$TC�����{���pK}D�4����3��7��fH4����_>Y�i|����s�#��]�������O��m\f.�b�}$%� ��t����K�D\f��J2.���)YB����<��i�Y���g��i�2���~�����o�o�/��d��?�]�1��GS�E�A���K��"�5}$�IE����G���K�p��ucb������T��������e�c�P7?����c6����ON���3
ay��'g�Xl����������t>�P�7|�������#-2)�S�M����Ki���(m�|e�2�d��6��e3�����z�}E\��f�������i��r0��
�2����>��(�+�F�u��2��FL���3P��OI~:��C��%10k��riW�k�9�Rv��701����F��|0'
�[m��G_.�9��P�*`Z�g>Xp���������Q���}�[�T�kr�Mq��\�Yi�O�����sOg��Ll��p�����o�m��7����.��u�6v��t�iN�yR��f�x�6�S�<�&}�����8���7����w~������{��������������n?�|>���u=���z)��0}������>U���mv��4����kC�?������]����*C k����-�b�����n���]`k{llI}�����S�,xr�Bd��1��aK���	��s����uw�;�����/
�^�t��W��4
�;]���%�����K�?h���\��pbYa)fC��-��U�+h�i�q3���d_O4�*�5�hX��Rdu+Ugau��V��?�0���t�D][��0���9��+�������t�(������}�O�9����w?��]^����fc��Ew���.��t��h?��P!�m�]\�)p�<71���T��N�*�V��d����0���
2}1��z\�u �ne$Wj1D�\q�3\���r���0t,�A��#�o�XFz��-��Nr���i#�@�;:-��]F�3�b~XJ�D_��b��!�9��5��#h�9�|A
��L���������5YH����6z�4���U�	i�F����������j����L���%+tp[��6a]��u�%����>I�GV��0��F@���&�hY���3� ]�3X��P�Kz�������z2����Ryy�A����J2����s�JjOGu9�hE9G���GI�L�(B�b(���(���yD�m�ugS�*�������
� �q��,I��	�Gc��Ea�9e#�s��	� +a�d$q�ZL�����J@��jI��X�Gf@A?�hs�K�&tm�2`�G��F����18��;�_'��]�B2A\�Ihk����I*k��?�i�����<'�;�K���AO���D����Q��x���v5�"�(;�������',hb���cE
s�Pi2�ejv����;4n���Q1&��'_��t���$4�y�Q���\���`��A�
��d'�^@�� *B��MJzIh�z��J\%V�Q�\-Gus�0JK(��@�2;Y��A����t~B��\�9}��dF����e7h����2���&Ntc��n���PVW�E
�������*�'�+a�����:�_�-��R���Lf\��7��c��]Ig�}&5�)%uISm��[)t1�<7u��;��a3WU$*Hh�Y0��xy������)K���9��~�(tF����,������qH��!�+�
��PrrY�������>���`V��FyL�/X�:��$����!}v_�l����n��)��������gPB�'�����j�Ny���J�*>:)�4+��.�mI��Dx����uw����m�Sr�q���+���t��n�j�Q�__��)�(Jc���(�Q5D�
�A��)������X�����/h)i�M�Q;j�z�C�hn1^�zOz;\P�������gP2P������4�SZ����w����\j�sa?�I)+�o����%�~�%�G��l9����	QQ��A�0Pf�F����IO��`1�t$�&[��HSw���)��*=2]�eb�:
��m�v�=o��������C������$���[z��.k�1&Z�9�M\a�����U�lft����pZCL�6l����-j.���\��;�}���:m�Sd��W>M���R�U����-a�Y��
M�8�v*VX�0oP�>�'�lR��sK{�v.�*�2�B*�H�(c�q+��D�Q�;Wm���a�E���T�eE���m�\H��+�Ki��b�4k���|g�1mp���h`0��t�L+��5O��le�N��F���S��}8$��8�K�`�������j*�����j>��R�H��Nx'�G+��|�d�e��t�c>��&J�u
�Oi0�`������pZK
Ny�F�o��{�E�1��	lyX����}u�����W�7�� :�uU�9���~)�0�dN`!�$E��?Z:��)-N���d�i��s��B�
�LX�A~��<$��3��	y��!��
#:i��0���m=
Q��z����(�jiJ�H�l����6K�g���K�B�L%#g�5mY^����������$2��_��(�}3�}s9�.�}��3��u
7�[�������a&Vi��^�20R?2��*��r�jXo��+�M�=�V)�����U5���s�TA�d������
�
y-<���D����,I4e�2ZI���
�>1C1�I����KY8�E�	���qC���OL�����:F�+��?�a���4<����lD�D�!F��&[��>i�6�(U��S���75>7�]~.3���6QW5?G5����g���GA&(����r��8?���dW�|�*����^nX�t�8�g}�R_n�����l2J��9���G�u���J_�P*�Q9�
���dp�l�&��1�[�� U�E ��Y�Rz�d�{��������g���?#���z����_�~)�eA��b1���Jcs=�����w#RK���9x��TL	����0�k
�m���Br��8�X�g�9�X[�5�t�������k|s,6�6f�/�����1�������|%�
Z���e;d��+�^�-�!�Fzk������9|����a
_u��Y�V3��
�%���]��4���i=����_������,S���hK9��R��4��;f�'cI}P�T������D��\��cE&�Dja���=DdP��~�n������'/�>X�e�2d�5����t��kHq��{I�m9/���X�d�E�cV��8�4s[fo���K���/��9f��Y����*TxE����<�p�'^��_�$����L��i_�)e _�N|Mt���Qu��<��J�[-�����q����D��q[�Q ?���a���?����-���%}�3#M[������C�h��m8�52�on��D����e`J�S�&+L�����:%�Y9���e>�i|���H���}��c�?�����y����a{��f�X~��}��^���7�I�&EW�� j�uF��z�*�g�w�
dG4�Z���>�
T��]R����3<���f}���j��o�:M.a/Gf����b�|DPDc:��i_[���U#�K��GX?�����{|l���<�E��$m���2����s�R���h��[����x����#v��d�J`l��p�}�L8CJ����m�*
�k6�q�����7D~?f��iRRv�����,W}~��n�yA��x�r442&M�:�i�+��k�_�L,P���*���R�}s�2�=M�d��=Qt���s��d
�	��"��������x^���{�M��\��]y�y�u���0{�a���>�E!���G���!\�(p��g����nn�ot�w7V�/2��7-$��qM��;+�8\�7��%H)8l��Ot�����<��i���<@�2����)h$������.�C��7��q�a/�
���,�5��Fr��r~�������j?��hWzA�*f*20�yA�n��E~f�#���U>6���Y*��hD�	 Q����eoD�V�e��Q������8�����h�9����c��_f.�2'�>a��#Kj��V�Lz��������uU�;p��eh�,8�3��J�rj���i��{M��fd�x;�Lj?��?;M��g�D�F��u������B||x�3��-2^K�`J=Z��Fk��b;�}!�;�a����{��~z���)�]PD�t�����
���OS���#����6��_&�i>7 $���C�����6�,��Wp�6�.H]z\�n��"G�zm�Sm�&c�P"��%�� f�W��7��.������oU��R�O�r!)	��,�*:}�c�,��bQA)�����!����-��a68rI�{%YB!.lY}#5��:@(b�Bhk
R]0��G���Z���k�xE/-y%�b�~
~NW�0���#�>��/Q�<���
���hey�����a).b�zP8����+��4�vl��s�E.�"���*FS6X���;����<�N.C)����6��I��D��CZ�]+�SB���;*R��?�d�P��R�#e�jy�4�{�D�.~��$Jyy[Q�/-�&J�*a��������,'~.��z����r�m5�G�jH�c�NA�3~������5wIL�I=q������l�{�j��:�(�^�9�v�nW�����Y�~��Z����>��fy+�����y_m6E���n�:��?��������n����PK��	��'�PK���P�G# 0005-parallel-backup-testcase.patchUT
X��^X��^[��^ux��<iW�H�����vr����@d�	!��<COf^Y*�dIQ�,������[U�el��:	Z�n�}�R��������j0��mk���o��6G|�c��z5~�������=�}�=v���f��.�a�^�_;0�l_8c6�������p�	�����L'~�2��>��eso��_�3+�6��nm�^���V�W������h�}9��<�������7�����e#�����"."��Vk��5��t�Q���3��1��r��'v�%?����l��Sc}6v\����M��A�O�0r|O4�[5f�Ha3��������d"��#��f�~�Z�v�c�nO����G�`����y�FR�"��x6��?���=���lq{��6��zs������w�������2�����\p&����7���=��u{pc�+�;us4����e<s�����H_�N��[���f4�Q�,
y����$����]�~�8�����'?��x���e;[�����$4g�����_5���r�Cj��(? ]3@m8P1��>�c�#>�P����U��!Jx�Mxd��
�m6f��)0���#6����	��C�����4HU�
���o�i��9w#�p��M�R�������='rL���3B�����<p�Dr��Q�������Lj��(4��_��mFf��r�J�g��
���"2CT�7��@�X��;C3D=���'���+�_r���Q[_�>c��`��1f��������>��g0%�F����cf!��9��;�=��� ���n��a7S��2tj��#�s�G�����9�����k�c).���:�up�M?�CV�L<Y(6X�����k}�J&u���������~Xo���A�xQ��i!�X��)��{�?.�^3$��W>�Y�T����}�� k#%{��n"���
?�;.CX��7��_%Z�
���v�Z������pA���2�6���(���,�=���V"���m��r
T�.7�`��M���3v C��
��1���G�Gwd�S0$0
�h9�.!��F�!��5�qd	���j��\��fg>c~����g\6�s���#_�����@�l#�
T��.\���6Q��n#`N�������B�^C�'�7a���J�&�3�]��$9����.G��L�����E�%���0P������u
d~x��3�6c/��1A���V|c�DA�M�0��kH�����������r����}P����!Ra�����B�����/�!v����	��14S
��!����P�D`Z���K���G>1��f���{���B��*��X�@�Jq�|Z���������?��_i/�S�|�6��PAS62q���bRp9�!n�Y�������'�3p�6�CC����<��}���4��G��L��+(p� �^c<�.�s#.B*�8��tqxrxp��o
��csXI��HV� �+�|�;�#�
B_����p����qzr����v�����!+�x��c���Jyp��=�sq�/]U���.��	�CJ4���Ff�F�^���yZ���l�������[GD���Sz�3��������D�P0��x�.)@��!V�����O����W�u�P�f��!�"�"�y��:��Hi���Hdy��0z��&�>6�Pr���X2�>�;Dr��;"*����]D;;;�exAW�>�w���|!o����`�}Pq%�A
QMIi�����& ���O����d���������p.e��<�,�k��b ��j��2���b���
�E���\�>�h��px��ba*�Zv�$���4a�T����������J��+'`�W8�m��gIU�>�<��@ U&
x�a.c��>��
_HD��*�#�8���7Xo���_�z-��Z�&�2�4>����<���`�a4�B �Y�f��#q�ra����LL���<��4��&�[-)>9u��:�j��RTi����D<H�b�r�3��y����������'�����N���������+�`Xok#8^�GP�y"�3�Z�Y��]9~��u+��xV*b��}I\��\�?���2m�P CH�@**���c����$�HZ:�������n���\�z�Q���S�X��#jpU��{��SV��I�D<�@I�.Wxe���va!M]0�B\I�B�	?���w��i�*���s��(q^�1�|��%j�b�CO��/����)�YC2.r��2
�;�$����O���`8X.�KIZ���l2q��ZR��A���$�i�3Tu���(���.x�f33#e*$Y�c�}_"������.�Q��})�z���X����Tw�����W���WBf�/��_��B���D�5v3H����������&�����c�#��s,V�*������_�V�j;���b�D���B�'��u�t�rO��sq7s�Jt���s�5"6���~���d<I�;%����07]��C`�a�tf�lL�T��jK�?�ZX�: ����@|�n�$��qg�*��f�`;F�Pv<������/��-4�J#ShHr����c��@����1��z�'�<oQ����2�^uN�}#V
V���r��������R�hZPq�p-��N:��A�}/��g��6�P�zE'�p`e���N8�.��a`
` 7&T9��p3q�z����`��d�-N�����6`�~��s���{���Z��;;�I�����ufRk1AT��;t
aV��'i&�B�C�<�&~:��\X}��@�f���o�t�8�?8dj:;9;��k���+4�P�_m��>k���+Y�M=��_��|��N�B���,�����/+���|�Q�G(�U�-����$��,A4U�U�d�QDZ��.K�f:���eXZ~A���!GR�(-�1R������ex�����$j	_��v���1}��:��@����B��k���C����
?�i+T�k���M��^e�������ZI�s�>"
����S?�;��N#p�Ba�D�>�P[���y��g������V�2?_6A/`(�^c�R�[��Qng.E��[O�������P�����X��.�����8�N���Roaa;\���`�(�)5��9�L�>7�r#�lgCa���i����{��D-�NQ�c/R?l�]F:��h����H�	�"����?R�l���5�d+t���Lr�V5����:�f����%���p]���u�|�����k����$��g�,91#R��Jq)��+6D�V.�_��I,_��\Wqu�]l,������Q3�-�m�Y���������x�iE1�N���$GT��5Mj@Z�O�tzf %,}b�-	��@�� RO�*J��GC��bJwn��V��d�\�q������-I����szV�0<;Og�K���I��r��%������E�$W�<%l�\)l�J��Fn�.�UN��=& G������ -�J��J��c�7P��P����������a��/`y��������a�l�
a�=���bx"RFw�����F�y�w�.
LOb���FJ���,����zr[pI9�w�
k#��,t#�~Bgf�g���}<v�y�S�\�E����I�qNp���Ai,��YVn�:�n;O+����������#f����/���~�����������3���{]������
A��7���z������62��F�2��:���>��4�W%[$dX��=H��D��S�oY�[~��ZfkR��|��%f����!�h{~����/�
�E��!���J���x�]H��0�K��"Z�������'�>�K'o������~����x�@,;�5"(c�����.����qS��(�4�rx}Kq(l_�����"C�T�����=F�])�wD������5i��Y�kP�t4<�������?�~8<L�����c�XI����i!��seY�"<��m���0�H8vrq��x�qJ�����q�C
�����K����O2!���?�]rL�����ZG_�|��1��T��M���:�����8?�+d�G�I�i����}<S-@-�'�.���������j���
v�u��e����'�%"M[�
�,�������6P� ��G���^W�Q����������U����/2�k����������L��H�$�.��%�n#]��"k��9�ry}���c%b��0]��gg���L�M}���|@�X��������R�����~�|G�chkM���C������Oe�0����Me4�N��j��B����_�VLv|zy���d/�q<�Gg��h�7���s��C�x��O.��O�8�dM���i��3C�G_���0�^�6��@_���
$�2$
�H9�Rr���AL�!����l�M��$���[WL8j1�����@�`S�����K(m2>�l�����5���
����FJ4o��z�������6�s�s�(���z����hN����#K�~m���K���vk����95E_=���-���������u�������c�E�y�e9c�E1rs�+J;;O����3G�Ll�,p,1j9���!�o%*�=�-6���Ie�#tb%E��E�Dk��;�-u���1��^��q����)��R��J���U���<}��PJ�p���t^�.R����w��T��z�zD�j@{�[E}����Jo#�������Q��q>�p�xM��O��=O�������&�����������(b���}UP�G9�����df�M��7������fM��j��`��g��Oyt�v��U��PK��\��GPK���PrK( 0006-parallel-backup-documentation.patchUT
X��^X��^[��^ux��\�R#9���O��� �6�1��G��a�]��zg.66�J�5T�jJ*���>�����\fJUV��|5�;qKt�V�R���I>�T�����pkk��w����z7�L���V8����`{w{�=�����T��E�����{O���������{6�r���,�	��������gr:��n��[����Q&��?dGb=���7x��go{��^�<�*����ttq�#��l�{a)�x���yp����B��H7R%�V��i�{�:���8�L3eT��.�b����p{����S����f:�s-������0z�&2�3�LE�f��m&-2dM���h�B9��Ng*
��w�9����LBq���x0�����nw�w��A?����~��3�$���K�{���g����v{�������7/f�*���� �!��e"�d@�`�
��x�����D�����Hj#������k��;��l��z���[z�3"���"x,a��btvq�qt����H��k����Y9�d���d1��!�<|�����E��������H�ht~��i����������	3���������ae�
!���m.U�r����x����U����t_�h�2if��	��(�r�L�4VUN����b�����ba������D�,�f�|�Zd�(�W`ml�2��~�2�2�t"�]2���"u�4��4Zki����%��ZXV�m6�����"�F�,���	ejB/�uOX�@R3��@N$/`����������q#����pJ�\��
��\z���P)�P��<��A�fHB�����N�E�Dn��|{���y%����it��:�J��;�i�fs��<K�T���Y��E�r���1J��Sz&~���A<��S%���y<�=u�'2���nf�L$6�Lb~+�<f<Vyb�2Cn83O�Dd�x�9����BIX"�IO�.#�����3��+���@�'��
}q����Qs'���G9����X0PM�����T��2��	�5d�G�P�I�]���]}d(�|:c}��G�.� ���u�pd,�Z��[�[0�(�3�(��5����q��������[`=>��~��d�I��oV�>��n�.H�� ��@t�x*�=�-B5Nd�&�i������H9�`8��O�3\42*�����Lc"�s��(��[u(���9�yt�RX3��'�9�1]�p�\j`�2�b���h�G���@]"�����U��~Q�&f�D��G
:i7��A6�MH&� �k�+����H�Q��d
��Fj���a�)ME0I]��QU����������� �v�^�c
@�=�*K�o=07`>�<���P2���
f�e1���:�n�e��b-7�G	�}�(�������	#a�@��eG01��)�v,����'0�k�r
�#�����a�PLx��.�5[K��b��/O�����	���e�l��g*�BTO�f���J�/���I���� ���hn��2�(\q�bvk���?�|�CU�����������d�
�F����l��@�?���
�������?W����*�*�z���5��B�z����]�.�EJ����i�h0x�������8���*��~%����/%����@w
�A�&��������d�17�"l��N#�@e�yB@q*��?Hf�C����X�6�
�+�x�Z�%{���d�� 1Qy�R��c�0Z��a��2'�(���F�xP���������<:n�4����-�'2�zvGe�<�n}�O���������sd)3T2r5%xD�Ub%)�OG�)�!�i�Z��3p
�?�5���@0K(�Cy��n�
�>-���ZA4��Xp��������0�����7.G����������l��PD1�b��H ��K1�:0A,b��1���8���,���
�����P�7�z������|��fy�a��uHV&|Y���`�<�1�������B'e=��``j���R�����*�oD��M�0|nh��4@p]�|Cy����C/�M��'�P)\�>�������	N���pvx~��4Z�2��5���[]y�CA+�TFq�n��L����2�e!}k�T&�1���;���%�8����Tef <a8�&h����r-S��c;EY6����]�������W��qN=Jy�g��Mx�@6�A�c,U"����|��M$y����"�)���,D�$ Q��U
M�����S�&���r:3���9,o��Q~���L���a���	+
	�pr��K���H�7kS���~�����%s6��V���R�<L�����po�����X.$�TK�	�HM����+��M3P��f@�
x57�U��a�@=���`�2�9Qn�6����M��T��������'K��h�E�o�nKN�(����M���gA�J���a�o����6�
9��/�:���+Nr���ig� �e�F�?B����ea�.�!�	�9��3K2Y�|�t|r�<A*,KH&���$�$ ��Ri0���~�z�72�{��/�\-�-���F�J���������I���O�M���1>����.<�3@���R�eC�R�������yp�IZOu}�`�M��HX��S3'�W��Z����=�5t�5��Z���&���{�����u0\���Uj?d>_�C�}9x'dG��N�v('�)�������ZE��f�(�jge���X�rA���h�uO*������l�

���>�.F�TP��z�L5�V�������DfK�y��;�K�{H�PHP�B�G>������a�W��!l���	hn�h�rX�x~�U��gD�B�Mi�3���j�p{���m�5��I�+��
�	�������'Q���y<V�������x����+��3�b+�lU6f[�+�0<���J��X?���p*ym���]��qbv����������|���Z��U���
f��`�+ ����Z���[�6,���,�0���	��������O�6���iFKEx����m��� E���1��,@���"<
�T�,Bl
��A�"��X+7������YUj��M;���6Y���L��wf�'*�t�����4Z�M�_��S50J;(K
#6����d~�K��T~w���g�E�E]=<���\{,�2I�g�h[����-�4q��Z^%�E��wT�O���$R�)���������Q���������{�`�$Ozj���
��'`�W�{�Ul���{�mw@u���g	]{Bu�'k�������FxJQ�x�_�`Q�����
]{|Ap%�tK��f��
�S��d�NG�m�.�$����d�{�n���\}q���D�bWtP�A�������H����)eU��h���z�*�X'f���e�4fu|>�M��g(�78yQ����N�r������O?��K����X
�f��-��X.��`�#EL�u�Va��z)Y���7����~�k8Co[I\�4�M�^����p��6�8�iP�En���u���k���n���eM�O����
<��H����lz<�����+��t����L�z���g
V(h��x�������Q����! `�A�\���!�s9Z��"��,F1/�����fh��~�8�fc�0�����U��v���G�?�Sw�=y���8����,�:���K��s/��v�������?���#�Y2�{���������o�zQ���l��/R~���r��!�G�cp��
�C�gT:?+FZ��e��7tJo���Mr�c���7�����.�A�/���"\���������t�$s�%�����kQ�r������/x�|���z�w���
�?��a���uY����h����(2B���
�H/x�M�%N�E1��X�������!�!��
����.�M��y[����2pR&�z��g������r���|�x�L��������+�O<��>��b`�����#��+�^�������g2�^.f������������)z������Xz~q?��g_�b�mN��<�]�������%"�URX�]'+�Je��Q��Oz�@�B�nw{g������}�������5(+F������P��`��k�V������PO��f�Y���k���}h����=Y3����j�?<���Y��E����7��?����S�j���7�,��=�{i#�~E�{��G�����E"�u�?��[�_��LD`��T0�e���dqI����P`P�\w��b�}�2�C�������+���M�4���wG��n#���u0����_��u~�LG�M��(��UHA����������F�}O�uB�F������c��n�;�]�h�(�Vsq�;\��2~6�^zV\�������g��w�~����l�Z�PK� G��rKPK���P}? 0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
X��^X��^[��^ux��Y�S�F�Y�+6tBl,��6�SBLJK�}��mFs�N�������6�������mH��2��:����>����(Q��v{t�[R��������V������VK_�g������Vk��A��r*G(f�0�9���|h&���8�G����+E&w�Z�6���Y$(��g{����nA7oU.�����v���������tZ_�S��L2�C�F�f��@��^�n��<�0����1
m��]���@ec�|����< E�J��hT M��aoNG�P�r(��|�����+8;�h���_�H�7��N�t!�S��L����w����#�Z���A��(�@l�L����U�������iy��a������~�����Z��-��Kw��������h;;v�u�t��Ci&���<���:.Q�%���^�������
��21�d:�cx*�3|Yiln�y8�OM&yz�7��1�B���p'"H�'CDL��4���J��0@[p}|�iW����)
�������cC�y��2F�U���"�#��8���F�4���#=a����
��p/�����Z�^b�s�_/��!�CKp5��8�x��JC��@%p?�0� '����	0���(���6��;Q���gZa��&�oYp,Rw>�b���f�nU��x����O��6x}yoe���>���3g)���$Gy"�%Bm��\+qT�����2��~����Q���������=�����G��{�1G:� ��7v'��E�)��LT=��rb���ks������I�S�q�L%�L]T�>��4�V��+
=UMs�����2�j�zy���Dfy�i���X�V��o���n�|�"��D��`�����@����{t2?LIg�kI%�:�%�0W�C=Rx.�cs���
8�1@c_��6�<)����)�$�2��	�&|���c��k���;�X��dJN�|hV���N�y�&�0�P�o�����L�w�z"��<�)���?���E&��b�a�Z���&�m�(�Up����Q��%��
������r����@/���d�O�-
�B�r��n�]L��L�`��0�Q<������B}k�k;9��]\�tQ-�|*9���8���,��(��Mx4�Z�F���+����@��3��g4m�e,�i:��Q�-S�ep,��Q�����	���s1N���HfTMM^H�$���,5b�R��-���zp�>�>��\�U�Q����\UM:h}��xGo?��������
-(�������	DJ)�}/���:8Z��4R��R��dM\�#�dYX\$�e��{o�O��?,k����2���Ee�PMo�jR���9[�����eZ���FQb#�$*��a�F��*�
 ���=��v��d�H�8l
���Ld�'�`~����m��m
M����H���>�_��T$X	�%a&bL*QJ���S�ko�?��f��
;<��5s�NA��.cj0k��=`�|�	N]�XN�+�qB��@�B&T�h�s?a�Y���&E?��	���z�}��������[Xh���bf+J$��&�BL)Q���G�A{��Y��cy��<��D<`��K����I�tu�v&;�[�kJ�.��������S�b�a����1��\b3�3E� ��&��X���D�z'�.��9W�cLU��-�UZ�o��oj�fk���[��z����"����mg��N������>��:V�E��bL`v����ft=�0�,=��mk�ZE�&-pE���e�l�q
iMN�����6��#TU�&If>�)KzHC�<BV�W^���d�����oo5i�����*���3��������O���989�Lrv�������9b��N�^#��9UN��y�`��C��U��*`�
�J�S�,gbA���qk@��4�0cmc��eB�����%y��*�$�(\�Z��PvEM�v��Ua�	�����k��0����}�E.��� ���.M��ZD8�����U(m�'�>q��d�cF��CO&�����\f��P�B-K��h)����c��d�|B�`��.5��E�r�&b�&��T9��[���~�gw����!���K�}�����f%!x����8.���t@�f
i�^W���5L�,A�����u�< �C�M����[�\�[�����;]�$����-3������e�,��ydJ���h�HM���L%�S|����hf&��*O�/���L�Fac�us{�C9B����}U�������Fm9����yM~�u�Z�C��?��.Ft��km�"'������
��l�6^�9�w�8(9J��2�t�����.�"��6%n������y�f����r����;����-�Rp<^���=����m ��^�~�f�f��r����^�����p������g�����^�.�:�\7{|�����j����������o�TX�xTO��:�D���
��y'j��C��F�'��4���Urp�4*uQ��V���0��Y�rw��������������w��j;T�d� 
�@U���#������S�#�����I��b(=����eI$�y�G�^��j��NX|�*���R�,�r�.���)�D�.W�tf����M��/������m��r�R�\e�a����f%rg�,0�7NQl�f��wa�o�*��SL��F�k�8B��K!�{��Bzf��)��3��L�(s3E��Y[{N<���$� �D�%�w������N��%���l��S����D?�@�V�z�*f*�+#�VD9v�|=�oE�������F]���_}��,�y����X6����Y��Hz�>��;�W]my]�����nQ��FX�qO�������+�)��n#j`��3�����=2����n�@�(L�C����0'S\��#�\"�E���W�?�~<�����
��G���W�N.d'F�����{����������m
��B��'���R�`�,���������b8V�(?��3��,B��<�X><K	�������x�R3�����*LIy�)6������%�V ���>�/�K��]�@��-��?�����A}Y���[�T��DjBx�����B���v���t�z0���Oa�p��Z��?PK���'G}PK���P�= 0008-added-windows-platform-support-for-parallel-backup.patchUT
X��^X��^[��^ux��Yyw�H�}���o,n���=���a�YC���^Kj@��I��n��oU�@�2�/1juuu���n�=w��L;fKW��3nt�Z�fu�n6�f�^W�m�;:�����(���5EQ�kds]���=�/��1T<1x;�f��[1��t�~�/A���C5����>o6��4E������_���{P�UU�0��&<Y��>���Y0u�������,��l���3�a��HR�\�����n9��L������-{�S��}���6��gF���&,�gfE����M�}B>����9d>�qM�dA���_]��F�����W�mV�����7����3g�M�B�
��s/�\�������6������P������V�y��$0P����������w�K�Lk:�ryf��/�_�@������n�����4+�P��i7�f$E��{I����{���V�E��!���w���9?@U���+�x������W\	��5���|"������}���K~=���\���l��g${�>!��=x+�;h��K��s�N#��z�(J4z���e0*g�7�'2i��(�W��P�-}�{f4)�y3�d_*��q�D�������v{������]�7�h�~'��*"I��1���e�}{"����F=��hG��&����dwm3It��?�?�&��b7���TL��J�������V��i���J��ZP��j�����r{���Z�~0���Mye�����55�����a_����w��q��?�G2�y0��h���"�+����S;��T��4�U���Z9���K���l�����0�Zh���T�l6K�J�����7�Ob�#��>�d	��]�t+-�S�cn93Q6`J�B0�Q�Q�
�R�v�����7-W�#��Cd�����m0L��������2��HJ�ECQqJ��4���``�4���SDb��,`�xN	��]�ok�!#�'(W�!����("��Nc�E�9I��Gt��*�����8�������3*�����Z�����S~'"}�L](�Qo�3bI�r�\.G:����c�=�94���9�m��3�1Sf~d�E��'3sY�b����J"��)Ja��pm�5�$"�L�"������>��N��y�3�)|�##���._2# �L+��1�����E��>�@N��6�)�O��Q�Z����~&��j�������X��E�R�/QG�PV���G*�lnZ,����`���Z,m�@Hb"V2y���.�=����<�e��K�!����pc�:r����v��n<w������h2�������$8�>b���������� �>��_a��[�����eb��?��+���V�D�
L����r|k� �hV��l���kZ��[9�'�7�g(��)�6^��)��`^�D�Vv�tb�b��p���kH����!�1���B�}�S�;B���B�hK��5�ur<HNz*�V��\�M�w2�,��@��Cd����4&�G�q�s��]�����l�O1:e(�SFD�i	�Bd=���1x2m�"������<h:��b;�M&�(Q�����C�$����fn����mRf������X�(�ZP�C.r�����������[XN�$��W�rRaC:�^.���}c��cU��w�m�X�X��`����x|F��]o����N\T�LY����z��/o�sw0��Q��&���W3]�����9?d~��<����n5�?�W.�U5N[A��=���{![JL�Q���."C�+���������?���ol�Gf��N@a�bv�E����-a3yLt������X�B�D��[���=6~��P����P�g�|�"���/�#C*M����b�c�\&��!r!��h�����)U��t�A�V�Q"�dF�!G4�A���HZV�&��ug�I���v�@�%�����\���T��]������{,��H,����uaj���"	2)�!w+����~�?0{������=��6�)���&��2l����1e��������'�u{�n;Y�!�/c�������2(D�����\��h�un�yE���:�J��2Cm1�vV�������d������'���tXj�EH�Q�����kk������g����P��y)��%'Z?�VF�m�B���X.�V�!�j:�/��H3�Q������Gv#qN�%�8��@��^�g���Fl�h1D>�cp�L�k�q�>u�t�q����mC��a��EKS�������Kn�g����(���������B$gn�l�����������U�/B$���n*fA���z�Cjqq�)5�Xo�:t���P�A�U @�0�o��}���p�%{�4�T�A��m'��C��%����U;���H��"xr��������Uc5������T:J]iO�gu�����>>k��GA�S?w�����W:,b"
���N���OGo�k�cq�t����:�|���9-�*��2������b}z������d��U��b��\Y^���������1�Y>}�k2�-�4���4����6
zO�Uj��
rw��pce��yI�?PK
L�u@
�PK���P�1 0009-progress-reporting.patchUT
X��^X��^[��^ux��Z{s����>���NA`�7�M�b���ul/���w+����Vq|�����gI��$�P.F3=3��u����%kw����5�v���g���:F��i������Y�3����l�Cft�������Q|dNY?vgl�K�g�e��ZD?~^���<��������S$�1���a�:�{�����b�����j��NN��w����>1�O,��y���E<�����b�Z-�8�O��}�}���m�r�D�[��/^0��?3f�Yes�m%t:���/��.�k�_
`u���{.r�b�������c�]�j5]����s3�����&<N`R��	�c8�b�����1���-6s�����s�\o3��y���K���]�p���j�Xt���U�s7a�����>��������J��c��V��8=�m;������fe����������j e�h����f��&�8N�(1�K6�>A>E��hr�8�46
���8���]�k���K��'�k�Z�
��%���V�������L�8��V�"`o�����$-���T>+�b�P8y���k�Tb�,��=pfE���i�K�^q���L������
x��0��%vGR=-4��V@�;l��r*&H����XS��������a�����\���Z��,��n����y�����vg�]�w�������'����������9Ud�x���YRvy�1Y���4F�h�����'�3b9�F����BT���:��f�vA5^��M�Jrc
0A���^'.L\p���7
�d�qT��T~D*?��e[����~��_~�9�/%��Ia
�C?����1���#��xw=�����~��n��9M����at�Z�1��Z�1�����%����v����:���	M����>|d��ed���������H�u��jp$��7�]_��u�����I�2IQ���F���A8��&����_UZ����:[�������E�w��k��y�Ah���TM��HiL����DQ�>S���{�l/B����T�Fw�i6�f�1j5}�����L!��U����loWT�^�$����%�!w��qe'���_A�GG�������kY������;�������r}�D�<�.��<Fq��K�%?DM�� 6�u��b��� p���.��1YpA}����Y�.nUM-w����������e���&��E ������Gg���E����j�'3�^N�fc���e8����c�X��il�����8
���@'���T����80�%�iE'\���ZZTo
����������-&t�K	�M+	��m�rU/`�;��1X����k��I�\�0zye��3!��A������#>��,�"01
{�U�V�5��0���(W�o�A��	���?���P#'$��7W���T:^�%d:��"��`L����$z,/b80���b��]v�b�;_��c}��Qi<|��6���c�@3x�*��{���Bd���kD*��5bb��D���m����^��.�do����9�\o>�gf���g��G�:�B�%9B�~ ��	��g�����~�O�����U��r]�K�qV�I�w�[w�$��.����N'�9�X�R��A�,�}��B�q�,��lL=��V�d�-�u,A8�B>;�a-G�d�P�U�����hd�M �����\XP�Q� �T���/������W�`���������|v����d5&Q����bf���(�Q�n���8��7�~i}�=���'�$�a{mY���4W�f�U���0]��M�,RN;X.��S�|q��C��2�56�I��������z )�K���8��m�U�����m��j����_��H�cr;�_g3��=���������T�y�<�)@�a;_��QN�La2�#����>�a��M*�nS�o�k��U����o�J��e����g�"��+o���E5���%�|7\��R��k�����o[O��(�/:��'������n<��A�[���F.�_1O[9����VK_���r�%����
Tk�����^���������Bw�!L���lb]Z0*J����j��|z2����
F����*�<XZ��7��T�K����B,yAB@�WD�j4Y����6��Yp����mO�Y���EX��@J�[�r�^���t]e�@��#���d����?�����wI���f��%��X�Jy!m����%��K�f6<v01X�_B��P���)�t�B���
��� $= nn�>@�R�R��+�E�%`�P��>;V�;����s�`����c�;:J�R����dF��J�G8�K�r�%���JK`>�Q�U�#��[#p��_�����"*�.���3�O���h-LU��<��������;���� �"���o
2>YK����i�N���jF�����o�",����=X�1����0��d��J�NYc���c�$������#D�� �Z-}$8u�s�u����U�������W[��m>������%)�����O��+���&[jP-�S���2b�3��,�R���(#hm��KCz�����G �Bd2@=N��
�R�����}x���wq���!�>������@'�$F��M���;��V7d�����q���1�"p����T*�1ptW��f2A�A>E���������%���=�VY<.���u��~4?]�:��������}�����:�GH����)�����D��O�Y������PH����t������Ka���t(���
j�Tn}������XH�P�������R�DZ�qJ�������D^i�5����/A�$�Q�S����oK�
��:�q����?��G����S���.^�%J`��*�<R���(�/�����!���F5��i���u���{�Ic`��<p��UA�%��Q�����AU�V�s��H5��p��`��J�XT#�x��B`b�����	\����T����;*�*,7QCa��*�E��(h���������U#�y�
�&������.�p�j������c81/����o&�L��	�H����L���uy0��
����8�&'I�BM8L<��rR4h�+u���FLTMq���Pg�k��D�E>dR��������u��E��1}�z3��+CY�%���S�?<�@�qx;�Y�,��d6~0$U��:��QG�+Y��T�Q�"���[S�����z�2S`e�#�?os8�/� �`��4�.n/���.&������w��h��o��p��{2(K�3�����]�dUhSU&qT.���9��G��_\
W'�
���/���c�5���Q,�4�c�H��!�rA�,��.�i��q�{<A'����z�n���S�"{�����Kw_)�������*�mm�@����0��*9(��a�6|�^7�N�2�J;��@����s� _^|��X0_yi��y����(���s��Ew���NSk��Uc�=�U����X���X~=�$�u���Ne�6�k��@s����/.,�^y
�m�*�jIPVaz(���	�3�Td��l�l*�2�f���|_-�BC�/�V��*t���=w��8x:BG3�"����!�����e���Z9Tk��������z���r�U}.d������K�OR�Q�U��X@
].p������E�o�yGb���0u������|�/<�-'7w�^g:��u��|��c�:
>��>�FO�����~#
cU�����L	k8�$wP]�����X�*LD&�R��7wI���(�~�q���K����S7��Y���:�z�V�-��m�;�C7�:�V�r��3�k��Ka@o6��F>���VJV�L]���s�Ht��+�D�]\���Y��z8������`|����?���18�x<��Ov������Qz]�Q:y�]]��{�+��_W�U�5&�Vfo�0���u[��]j������e7�nS�4zN�V�6t���vo�E�����|�'�M��7z:�!����7�����+.��g�-;��/�ez��k��s���Z	��S��f�����q|z
���z���wz:u���AW���=wW�����&�KRfq�< ��<���A��Y���|6��%�m���gW>{����(��"i(��"j(��"k(��"l(�u�9��6�����3qM�����z�f�R?���w��Qo����PK��s���1PK���P�Q 0010-backup-manifest.patchUT
X��^f��^f��^ux��<is�����_1�F)�%����2-s#K�H����P 0��DZ�s����`Re{�jS)�fzz�{����8<h��m:��t�����k����A����F���c�q���C9�}Q����Y�76^�#�������3�?�����_��������/6^��<B@�h��<M��8jw��D��W�o�K'>������6�	@�f1���(���V�"
�]|#}w7��������,�<��!���CQ^��Cp��u���� 8����&D���2�Mq�h������++�-�
1��H���x�3]�r�\t�T���F���o*#�\���t+��n
��d��E�r�"�{��S����
��LD�z����]�����mx�+?����td�7;��dr��O����!���i���k��TYw�_~�F�Y��Zx���+'"���o�����_�`"�k	����6od��X�z�)����+	����s���Ba����qL������Z3`��F���`�9����VS��9�� ��%�8�8� �pG/�)^�����R:�8,��y�:
�d0e��I�����z��)#�v���x�x�-�|�x�x�������C���;��*�*�Q�a�3\�$B�ex'��?31���"��ky���"�I��
�F$��J��,X�1�K����-�i(m��J{��d�i��;%��HP�8��h1i��N��a���`���C��J��k��D����'/��a�_�KBf�H��6���7��K�3N_����c&��>��sX���f|<Wt]�}���O�Q�V-ZLV�����_+"-�%�S��T&����{f���72�
�1��1�`f���>�b���4��3�e<������T
Y��;���z�!���[���"�]\E��(j�A�\�� �C��II�t�����8lT@���:������M�"@�f�7���';8F�
��I3/�@IX�M��8���<��xn�c��7u-������Z: |q�EE.�]�:��k�OPJ�����b�*�����1�+�[��{���s��B�L/
�5<Px�]��p@�U�G������$�Z��E6`��NeX�O��gV��thP��A�E�����a�������Kc�$Y���i�������D�lwg�,vD����*���`�}{�������CK�0$�wT�b,�[)}6[Lco>�j���OA.�t��(���X��r����f�u�]AEx��p����c����"D��~U~_,�>j�`����|��r�q(�{=��>X0��G7��96����j�+Vr�����0���/��pw�(��!��o7X�?
9�[��9�}:
�"��`R4�P	E��U_d�$�5��9K�=9U����>��R/g���������d� ��E�8c�����v�Yv�6�QW����W;��$��
���7c-��NHw?+./N/{����;������n`
��g���;�z�����7��_���\��������h��h��
pbG1�sP���%F9e�w��!��E"�0.��`���#���x<��(}�O�w����B���)8C�t��F���_��B���:�8�M|���6*�j�������z)#P{�q+�;t�����E����2g�dQO(-��R��&���zRo�q�`�"�~=��~��uD��m�hk�������mg����ZX�m>K����<��M,�,��"%W���L/��F���F�
�(<�i�r9�������%9�X�7l��	|�G��Zu������nH\h��w��W���y�uo8:�������RN�@��l�3^\��{������1���A��G������8�����Zl��*h!��k���Gg��<h��)����C��������Ax�DQ��������Y",&d���i��K�IxtW�y����}���D�H&�)���;��4�g�������M����^�lZ*}���Sn���hX��N���|8*��t����&K�wbM���a�"�"�e{�i����d�d��?�f1���?��@@+:��L��k���!�s~����Xu�s8�+B��p������A�`����UY	T���������<����f:��M���|��������:X��T�����%�&p��`��g��ewDi\�7���������_{>	�iS�A�q����b��q�V�88}�u�oz��������2�)������M���)���w~:z�y������2�����c�^a��3��W��+�:���Ba��il{>�X7A���[e�}����H��T%L����u�m�t�
�����  h��(�x���TM���z�"vEC�����;�E�"<d|�����$l(�����C��3��~������y��$��*eb$m����v@��bI
0`]7�`1u!��3���vxG{�5�,�iL�WF�f�\��aX#!P$�&����MH�0���>������bKhf���[�(H�!GAZhg����n_r����G��y�DL��������\/���a�D��������/^�o������c�����|�"�����xi�S$�,B�f�����:�!�����}�P�2w{�HW����=�2����D���m��H�����y:,U�!�z��
�Zt�{�xU��	�"��:�����e,L0�b(��a�%���>~WD�TV��\�4�&�6!�Q��"t*`6�,D���Qe+e�0������`�s�L��P���I�O�AF{$�z��.��_T&���~��@���8��2����"�@\9��|�+�,���������[9��Ls~�7u��V�&��w�����*5�ZI�c�������|FH����X�D!���������_J�rfIt�D_�4.q�Lg��$��!�!Z��C���+�T��So��7V�|����Q���FX
���0Q:�(�6��B��������:������SrJ�M���������0�I��#�@�y�0���_��L��C+��7.�
�G@�Q����5�Q����IaWK��� GB�5	Tq:��h��*���*��N����[��W+i}���T����u?@br����Jr�������HN>=��T!���\��8����@<
f�s/T�#���20P�R}����JM���l�/��j	����N��H���L"�����`neJ��d�p)�R���[���y��[=@d�s���	������m*��:tL-8����Q0�� V��FB��~J��e�t���Z��������K2j���=�i6M������:��Z�[s�#,�Y�8H�L�q�����\WY�|���L���t�`�=�VS�����?��G���O���He��_��^��,�/cT����g�B%���z*��p4I��:O�&rRr`���t]�����l�J"}�m�}%AF���k�	���: ��������a�����?��h��{�J���Xgo.��������@=b>D��	�w�"Wk)$dX�s�i*AG7X�Y*��FCQ.�j��JQNE��C���������(p�xg����V2\�o�#��Uf�j��`�T���F�.
8���0���& $�p	L�|�nYIS09qm�e��2�P)/���')�~�X&��d*}]�`iueH_s��K`�0Q=n)Q�H�^������<�{�_D�*YD�3o�U����m)=������j�i=��>���<���Vx�;%��`�*�K4�3Ym���X8S,�*|�G�lDpP���"Yv)n����-B�^��\9�B��=����^���O+���}&��!�D����@�j�ra�"�W��B�������V����2�J���>6W�[�z�r@B���t���+IP��m�� �A�Za�������3�^�a��D�tO��(��U*��y3���H*/^��p/��F,E{F��n������R�L�8���s�(]��K#���1�$��>"�l5<)TS
��y�x)�	d�
e��)��@�W&h�+T�83R�8��S��5��������50��+K_�Br��.��LdGV_h�c�N(�N��
��@���u@�j���d;���'	�5(HA�������j��\�V���0z���qB��J�fG�YL6�"��i>g� �����\�5G��Lj�����D^�W.gKX��J�J��<������x�,T�3.����>�d���@���*�,&���\��W��Y�znV6���p�����	����f��P�������
TI��@3��uJ�����!2{Xg&S��AxoO���M�	��u�
5%�~_�K����`�f�R���1�Q�{�k8k�]�F�Si���j�W:��Z�S�M�/Zs$7^��=Pf���+]X�#���:�B���$���+R������m�Tt�p�4k���x&��w����+������7���c�� �:T�%����
���(u�A������O�>nJS;�7�[?6t�������UVR�]L@�`q���a�_�+j!��ZK:����t�3OW�I��8Q���j{��WE�	�����BT�d �QW��Z8)��U��%N�N��Qs��8(l�����x-+�f�jp"U�X����h�5��|�/��z�{#
f`�7��)
�M��J8�i*w����HQ0�W3��m�����)�@�a���������tU"��5[�F(v���P[��G
m��6��BZ�MUU�P}�'��&Gs�x�@�9�|$n"����2$�X����|�WU�D��&NkX�<���������l�����v�����)�z��{�����xC���\1���tcHJf���D�>G4�P�V�v������SR��m'^U������[��'2fL�V��Y[Qm�U�/"������,�������G%[[QT�7���a���/�]�5/���������gR��ZMNl�sph���������Qk�D�w��*�a'sCp��5/c]����:����VP��5]T*�xz��,p.��C�����QN�fc8�glQT���~QP1]�������f�2?�Wh��7�Wy���-um�v��'Fk3�,#1��j��?�J<��.�a�z���c;�G����%>�u_����O��{������;�8��ew�[�Y	�t�+�
���~Hb���F��W*�
���s=��
�!������X�0�n?+j,w��� (��k,-�mm�[���(�y�	eNa���j�v4��Y�@1��i�>��i,��}!?63oR��,����[���[���A��/G�����,���W8�)lNEy��
Z�G��(a0a���1��VvTyy�k��k������-���b�a}U����#:3�v��B�)���Z�p�>��'-����\Cg���JG�Ba�=���"��b����U��f���
K_������������5-r8+����s�]k3�a��mz�y�{~L������s���x�����Ns���j�f�#'�q������L�?
�`��c�Ts?�~c�2�Q�M�EN!���N��WT����q�9)����k1.��+�	l/����@�K���R���>tm<��3�����_��t������;G
��zN����-9��)����r��e$t������~��wR��J����f���.o�&q�������#�Mofl��0����w^st2G���4�.[��i�EE�,6�G�Gb�Vy���3�����88��k��������+���L�F$'n���U��2�+*Ib��0%Y/�Y�t:��2|8�>Z5�� �v4�w��G������q#�JJ��	1�����\-`s������}NuB=-6@X�z]6��L�D��7���`����*������������{���)J`�TS��@�Gi#6�$�m��In�+E.�'/��Baz+�/7^����������wDu@v��O1_�����E�w�Lx�2���T���e�5���gj����iY��C��#�1n&Y�t#������]�H�z��9zO�
-���LZj/E����;�@�Fl��%���J��m�c��q,�J�����[�6��	&u�����f�M��]0X�Im��o'�[pF*�z�v����N=�|~���]pFR(�';$?Ig����5B�i��C�f
�(g�P(��E���2!��q�p7�}���b���C���@������P&����&H�^��%���G,!%�>��O�p@��-�����j��r�JeQ����PG����I&J�x=�l�A|������Jt�.o�u�A�B���r�6����@�H�&�}��u��z���t6_��(9��q:
��X��&��x`I����\��z�\��+k�H���?m7~����[�������e�6n7���!*����~H�g}��P����(Y�|�� �x~dc}6�A��V�%
����d��o��|��Kf-��5@�U����F��l�����o��z1^�.ml�PKd��*�QPK���P�% __MACOSX/._0010-backup-manifest.patchUT
X��^f��^���^ux�c`cg`b`�MLV�V�P��'q����!!AP&H� @S���J���K,(�I��I,.)-NMII,IU)L[=5D��1�\�PK�	ph]�PK���P����	? ��0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
X��^X��^[��^ux�PK���PN�$L��@? ��Q	0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
X��^X��^[��^ux�PK���P���;1��7 ��i0003-Parallel-Backup-Backend-Replication-commands.patchUT
X��^X��^[��^ux�PK���P��	��'�( ��)M0004-Parallel-Backup-pg_basebackup.patchUT
X��^X��^[��^ux�PK���P��\��G# ��nu0005-parallel-backup-testcase.patchUT
X��^X��^[��^ux�PK���P� G��rK( ����0006-parallel-backup-documentation.patchUT
X��^X��^[��^ux�PK���P���'G}? ����0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
X��^X��^[��^ux�PK���P
L�u@
�= ����0008-added-windows-platform-support-for-parallel-backup.patchUT
X��^X��^[��^ux�PK���P��s���1 ����0009-progress-reporting.patchUT
X��^X��^[��^ux�PK���Pd��*�Q ����0010-backup-manifest.patchUT
X��^f��^f��^ux�PK���P�	ph]�% ��W�__MACOSX/._0010-backup-manifest.patchUT
X��^f��^���^ux�PKZ'�
#81Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Asif Rehman (#80)
Re: WIP/PoC for parallel backup

Hi Asif

Getting the following error on Parallel backup when --no-manifest option is
used.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 5 -D
/home/edb/Desktop/backup/ --no-manifest
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_10223"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: write-ahead log end point: 0/2000100
pg_basebackup: error: could not get data for 'BUILD_MANIFEST': ERROR:
could not open file
"base/pgsql_tmp/pgsql_tmp_b4ef5ac0fd150b2a28caf626bbb1bef2.1": No such file
or directory
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Tue, Apr 14, 2020 at 5:33 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Wed, Apr 8, 2020 at 6:53 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Tue, Apr 7, 2020 at 9:44 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16)
and hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable.
The hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand
dynamically, I think it's
sufficient initial size. max_wal_senders is not used, because it
can be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

Hi Asif

I have verified the bug fixes, one bug is fixed and working now as
expected

For the verification of the other bug fixes faced following issues,
please have a look.

1) Following bug fixes mentioned below are generating segmentation fault.

Please note for reference I have added a description only as steps were
given in previous emails of each bug I tried to verify the fix. Backtrace
is also added with each case which points to one bug for both the cases.

a) The backup failed with errors "error: could not connect to server:
could not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.

[edb@localhost bin]$ ./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_9925"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
….
….
pg_basebackup: backup worker (1014) created
pg_basebackup: backup worker (1015) created
pg_basebackup: backup worker (1016) created
pg_basebackup: backup worker (1017) created
pg_basebackup: error: could not connect to server: could not look up
local user ID 1000: Too many open files
Segmentation fault
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.13219.localhost.localdomain.1586349551
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 13219]
[New LWP 13222]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f2226f76a49 in __run_exit_handlers (status=1,
listp=0x7f22272f86c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f2226f76a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x952ca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffe3dabc718) at
pg_basebackup.c:2765
(gdb)

b) When executing two backups at the same time, getting FATAL error due
to max_wal_senders and instead of exit Backup got completed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 1/DA000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_17066"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
Segmentation fault (core dumped)
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.17041.localhost.localdomain.1586353696
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 17041]
[New LWP 17067]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f051edc1a49 in __run_exit_handlers (status=1,
listp=0x7f051f1436c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f051edc1a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x1c6dca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffdb76a6d68) at
pg_basebackup.c:2765
(gdb)

2) The following bug is not fixed yet

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -j
8
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/A0000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_16235"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_hba.conf pg_logical pg_notify pg_serial
pg_stat pg_subtrans pg_twophase pg_xact postgresql.conf
pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots
pg_stat_tmp pg_tblspc PG_VERSION postgresql.auto.conf
[edb@localhost bin]$
[edb@localhost bin]$

Thanks
Kashif Zeeshan

On Tue, Apr 7, 2020 at 4:03 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error is
displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then
the backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-T /home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup. I think one bug fix will
solve all these cases where clean up is not done when parallel backup is
failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-j 8
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup
patch then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP,

not while the backup is

in progress. So if the backup is a large one, early error

detection would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected,
at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail
quicker.
I don't currently understand the reason for the prohibition so I
can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only
intended

to make parallel behave the same as non-parallel here. So, I agree
with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding

the shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands
you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing
the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string>

OR

(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands.

So that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether
that's
possible now or not, it seems unwise to hard-wire that assumption
into
the wire protocol.

I was thinking that perhaps the client should generate a unique
backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard
to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any
need for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared
hash table.
There will be one structure per parallel backup. Since a single
parallel backup
can engage more than one wal sender, so I think max_wal_senders might
be a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines
the maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new
file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains
the same
as for non-parallel backup with the exception that multiple threads
will now be
updating it. So in parallel backup, this will represent the overall
bytes that
have been transferred. So the workers would sleep if they have
exceeded the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup
as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this
structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication
command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a
backend process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

Hi,

rebased and updated to the current master (8128b0c1). v13 is attached.

- Fixes the above reported issues.

- Added progress-reporting support for parallel:
For this, 'backup_streamed' is moved to a shared structure (BackupState) as
pg_atomic_uint64 variable. The worker processes will keep incrementing this
variable.

While files are being transferred from server to client. The main process
remains
in an idle state. So after each increment, the worker process will signal
master to
update the stats in pg_stat_progress_basebackup view.

The 'tablespace_streamed' column is not updated and will remain empty.
This is
because multiple workers may be copying files from different tablespaces.

- Added backup manifest:
The backend workers maintain their own manifest file which contains a list
of files
that are being transferred by the work. Once all backup files are
transferred, the
workers will create a temp file as
('pg_tempdir/temp_file_prefix_backupid.workerid')
to write the content of the manifest file from BufFile. The workers won’t
add the
header, nor the WAL information in their manifest. These two will be added
by the
main process while merging all worker manifest files.

The main process will read these individual files and concatenate them
into a single file
which is then sent back to the client.

The manifest file is created when the following command is received:

BUILD_MANIFEST 'backupid'

This is a new replication command. It is sent when pg_basebackup has
copied all the
$PGDATA files including WAL files.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#82Asif Rehman
asifr.rehman@gmail.com
In reply to: Kashif Zeeshan (#81)
1 attachment(s)
Re: WIP/PoC for parallel backup

On Tue, Apr 14, 2020 at 6:32 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

Getting the following error on Parallel backup when --no-manifest option
is used.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 5 -D
/home/edb/Desktop/backup/ --no-manifest
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_10223"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: write-ahead log end point: 0/2000100
pg_basebackup: error: could not get data for 'BUILD_MANIFEST': ERROR:
could not open file
"base/pgsql_tmp/pgsql_tmp_b4ef5ac0fd150b2a28caf626bbb1bef2.1": No such file
or directory
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

I forgot to make a check for no-manifest. Fixed. Attached is the updated
patch.

Thanks

On Tue, Apr 14, 2020 at 5:33 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Wed, Apr 8, 2020 at 6:53 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Tue, Apr 7, 2020 at 9:44 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16)
and hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable.
The hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand
dynamically, I think it's
sufficient initial size. max_wal_senders is not used, because it
can be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

Hi Asif

I have verified the bug fixes, one bug is fixed and working now as
expected

For the verification of the other bug fixes faced following issues,
please have a look.

1) Following bug fixes mentioned below are generating segmentation
fault.

Please note for reference I have added a description only as steps were
given in previous emails of each bug I tried to verify the fix. Backtrace
is also added with each case which points to one bug for both the cases.

a) The backup failed with errors "error: could not connect to server:
could not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.

[edb@localhost bin]$ ./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_9925"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
….
….
pg_basebackup: backup worker (1014) created
pg_basebackup: backup worker (1015) created
pg_basebackup: backup worker (1016) created
pg_basebackup: backup worker (1017) created
pg_basebackup: error: could not connect to server: could not look up
local user ID 1000: Too many open files
Segmentation fault
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.13219.localhost.localdomain.1586349551
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show
copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 13219]
[New LWP 13222]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f2226f76a49 in __run_exit_handlers (status=1,
listp=0x7f22272f86c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f2226f76a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x952ca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffe3dabc718) at
pg_basebackup.c:2765
(gdb)

b) When executing two backups at the same time, getting FATAL error due
to max_wal_senders and instead of exit Backup got completed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 1/DA000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_17066"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
Segmentation fault (core dumped)
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.17041.localhost.localdomain.1586353696
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show
copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 17041]
[New LWP 17067]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f051edc1a49 in __run_exit_handlers (status=1,
listp=0x7f051f1436c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f051edc1a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x1c6dca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffdb76a6d68) at
pg_basebackup.c:2765
(gdb)

2) The following bug is not fixed yet

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-j 8
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/A0000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_16235"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_hba.conf pg_logical pg_notify pg_serial
pg_stat pg_subtrans pg_twophase pg_xact postgresql.conf
pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots
pg_stat_tmp pg_tblspc PG_VERSION postgresql.auto.conf
[edb@localhost bin]$
[edb@localhost bin]$

Thanks
Kashif Zeeshan

On Tue, Apr 7, 2020 at 4:03 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error
is displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then
the backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel
Backup is in progress then the correct error is displayed but then the
backup folder is not cleaned and leaves a corrupt backup. I think one bug
fix will solve all these cases where clean up is not done when parallel
backup is failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D
/home/edb/Desktop/backup/ -j 8
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup
patch then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D
/home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP,

not while the backup is

in progress. So if the backup is a large one, early error

detection would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel
backup
inconsistent in behavior with non-parallel backup will be rejected,
at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be
relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail
quicker.
I don't currently understand the reason for the prohibition so I
can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only
intended

to make parallel behave the same as non-parallel here. So, I agree
with

you that the behavior of parallel backup should be consistent with
the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with
an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding

the shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands
you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing
the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups
will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string>

OR

(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands.

So that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether
that's
possible now or not, it seems unwise to hard-wire that assumption
into
the wire protocol.

I was thinking that perhaps the client should generate a unique
backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way
is
better. Either way, the backup ID should be something long and hard
to
guess, not e.g. the leader processes' PID. I think we should
generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode
the
result to get a string. That way there's almost no risk of two
backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing
a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause
a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any
need for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared
hash table.
There will be one structure per parallel backup. Since a single
parallel backup
can engage more than one wal sender, so I think max_wal_senders
might be a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that
defines the maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new
file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains
the same
as for non-parallel backup with the exception that multiple threads
will now be
updating it. So in parallel backup, this will represent the overall
bytes that
have been transferred. So the workers would sleep if they have
exceeded the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel
backup as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this
structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication
command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a
backend process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

Hi,

rebased and updated to the current master (8128b0c1). v13 is attached.

- Fixes the above reported issues.

- Added progress-reporting support for parallel:
For this, 'backup_streamed' is moved to a shared structure (BackupState)
as
pg_atomic_uint64 variable. The worker processes will keep incrementing
this
variable.

While files are being transferred from server to client. The main process
remains
in an idle state. So after each increment, the worker process will signal
master to
update the stats in pg_stat_progress_basebackup view.

The 'tablespace_streamed' column is not updated and will remain empty.
This is
because multiple workers may be copying files from different tablespaces.

- Added backup manifest:
The backend workers maintain their own manifest file which contains a
list of files
that are being transferred by the work. Once all backup files are
transferred, the
workers will create a temp file as
('pg_tempdir/temp_file_prefix_backupid.workerid')
to write the content of the manifest file from BufFile. The workers won’t
add the
header, nor the WAL information in their manifest. These two will be
added by the
main process while merging all worker manifest files.

The main process will read these individual files and concatenate them
into a single file
which is then sent back to the client.

The manifest file is created when the following command is received:

BUILD_MANIFEST 'backupid'

This is a new replication command. It is sent when pg_basebackup has
copied all the
$PGDATA files including WAL files.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

parallel_backup_v14.zipapplication/zip; name=parallel_backup_v14.zipDownload
PK���P	? 0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
��^-��^%��^ux��Yio�H�l��6�-R�ay���W"l&lg�EM�)qL�3�����nR��(�
��"�]]U����yL�6�����;m���l���q:�^�w�k�������p�C0z����?�t���Q�!b��K>�2������Ww<
���NY��#�k�������F���9l@U���v��p+9�O��'o@7���e�l�!v����=@�=D�N����I}+q?���d17�u��
M�������+���=�b4�Yi�Wh��:���}��������LP����[�����0L���Q��GB�R�,�����B��i��8P���Xs#����i�o�{p:f�mv��o4z�~�:�������v������g��_����^�AU|�i�D)�Y�:<NF��|����'(�B_%�6�(���J�(!_FP	Y2��}�5�y���^N��V�J��XM���[gUf"�!�x�-�b��C�s��8?gT����Y�k��l�j.��3�j��Mt�P���(�!]������-\�4�3A��q.���LN?�~2's�<K��|��5^*xD�7BU>Fn����<�`-B'�9.WW�e�#��|�6Sg�6�tu�����\�41{�l+�T�u��5rt��������t%C�1&b�L��o��(�
%��U_��"i���
�3�F����I�Nk�f�C5�AT��U4+@�2GC2��\g���K=@����Rb>������4	��EZe�9�6��e@��8T���))�<+���C�	��'`�
O������$~��F���Q��]�40+I�����x���d�?4T������r,�w=��O�r�$�����z &75I��8�:Y*��bN[��jb1����e
��!B��Z,#WW�:�K�P�z������%���R&��=�z?89����jx�nt:�<;����o
�}x��/��zeH�lVDB*x)�	E��oyc�-���K}�Gy��3�$���
�wCTU�0�V���r`���|?�vxAr���j�q����P�����8voy�gK����y`��/F��[���4�t���RS�?,]�|�\jR0;0Q��#qi�@:hI��q�Hi�s�f :&'IX�0Fh��B�����,%K��L�jW�v2]=�]\%���U��Qf:L-"QTC6��yT�<�(r�����`M����/�����^.�ju�I]��_�ptzY�K&��������F
vU��!p
�������n&���*$v1���c�4�Ns�W�������R�}��Y��I���c�H��cb����)�:=��8>b0��������(D��(I<V@L�=^E����k{���WQy��t�5�M�����<��f8�1ow	l�K�w�N0���<0����>]��	����������U`��Y�Y,�#���J��O���,Oc�@�|��$3�[�F��P������j�rW7��]��)aO�;;�����������V���d JU"8�D"���H����)�p��L{���L�unR�B��$�a��>�.��9�W��|�
��}�Z��sx��h����+���$��8���v���	5����>L�)�!@����A��a�y��0�~�<��'�>�P�x��7n8��2�B�R�w
��
(���������|��^ls	Y���������gQ��Q��=W�����������4�y����sBz��p�$��s�d<��K���rb�9�������['"���D��o��M*y,N�N+�!>�2��/�%_��+�!�_���+,���)Z�z=L��sjQW��A��E�h�X�L/�n����--/�T��MG���Zz�f����(�=jss�a�)67�lT���>���i����'��b*��)=��Ef����-qn�q����e�	:(7�����=Y���T���3w��b~pJO~�c��D���t��xi;��x"|���U���H�l?���������������MG�����m-�����C�-"���\w������Tvd	z���\j������aki�j�Mm�,�@���:s�a���1;���o����{=�n�mc���^��p(�b�C��x�<��H��E������>�����~���~i��djC�������^�}w�g���cE��z��[���j$F��xpuv<8�����7�9�Z��j7(
�����M�F�[���PK����	PK���P�@? 0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
��^-��^%��^ux��[mw�F��b�=��#0�l�iKl�x�q|���l��#���Vu�M���{g$�a�Y��i���;��yf�o�`�F�c���[����I�>;;�������q�{�r�O�G���|6!kwY�uA��N����1��c6����,������Sw2�M���ze%���e���V�/��.�-�['�Vu8�[�����w���:���g�=��$�X�Y��y���,	�����b�"1������c��O��
mf37a���,y�x�����Kx�y0��X#O��e��Y��=�<s��+�%�r�Hx0�U�X�4�����Y�;4����	�pb��%��?�Q�!U��z^,��l��}��r��+��B�
0D,V����ZE�Z �P=�g����L��Z�;4�*�#��
�9�q|�D�[��?�`���|e��#�����S��sm2�!*-u9_Y������{sG���S��|��;�W��2���n������!j�n���O�'�z����1k4&�D�O�~�t���;��n��N���>>k6�g��s�}��n�N������X�l4��?�F�u�>70���SO�=�f��4T��#����`� ����`��L�����b�9�\34��r����?�f0�00/o����w��QL��<�h�$����^���"�o5��l��.��� �O����W*� ������!��]�
��b����T���
,�A2���v������U@�G6�C����dV*�J,hZ��>��J�ov�������[�.?��=e#Q(d�N���t40������k�,��g��
���iU*��5�������
I�Wlf}�F�?�[���h����
p��+7�f��]"�D�����&�����O�0I�@zQ9*v�+To��A�CEX3l��!mi���a�cL��GV��Fj��3"�y�1��{V�	<I�0
&�9�P������������7���]����y�>�����63�������������O���]����k�!My����!�y
�|=� �
X��XE�����?L�j5b ,[e�
�w����b�on���O�UA{V*�����������[����������s�/�6�k�_�����A�K��G��r�Ed��8� -9�+z	�~q��Ba���q2�|/MFa�B�F�G����4����+�b_�����d� ����"4�CP9�R+��A�������x�`�o��@;G��7����?���������G�J�|��=�H5�d`*����Z%�#}P���,!����J�vED��O�����[C>�Tj"�f���gs�!����q6
�����������.�����g�<�tx����/�- ��\�_-+����4�@�&"A�����������a	�k��H�@��9%F�V((1�4�m?-)�xy5���G�4HE��2�
��qcL�s7���<���	�:�h`�"1`
����W��Z�PDRTL�9�fE��
���F�M�H��&Z�y��n=���Gqa5q�k�hL]>�����0?���
���0�|�K�sah�����b����/��@��i�!�*�F��`Y����� �yLE<La��d?f2o;P����U��g0 F� 1�f�W@���H,X?��P�_����1��sU5�X��b��zh3��������UtV����J�����Z�V����"�KC1q?���a�\��Z5v�F[�&*���T�T���N�I�]hu
�����JF1}�I|�>�[K�Jm����Pq����jZyWV<�+>�RzmM����Z��Z!T��|3H�����2W&$GB�4�w�rK�p-]=�G������P���-0�x��Q���,	�B4M��7��	+�i�`8���w��5fM���R�����;���0))X7�����\~���o��{$=����������U=m��2S�n d���8v���Mj�=YZ���r�(�J��{�A��gi7�Vt��"k~i����t��2Q(�=k$�6������S��sr|4���/7�d �'��R(@�����W�D��9AI#�fP��*�r���-�o�V9U��,t�#%����+���GOV��'tYEH�*>�W�Q^�F�p3l�����^����	���"�������~^��������8�F|>�1[!~�;��Kx�W�/�B�+��� ���0������n������+o�����
�+A���E\�m��W�z%&�\�M��'�h�>[��p=����P�\��B>��Wbv@�:��l����p<���mP<Yr#����|S��F�|
��;�w��U����;�x&x'���K�^��g"w�l�.�T����X]6�����+���D�D���.���6j������S�L�	���l�ON�F��qwT~�T*p�����������5���N98�p���z7����{�w���k3����7�j(�`�%�
�0��-t}��J<��hCx��T{j���+�Rk�D� �SBvp5UWI'�\k���O�������b&�[X:��|����~��)b���\�%{���j
D<�]y�[�z�����`:	 r��-��X���F���e��G#��s���>a���5�t��JH�z��H���
�\�k�K��PLn���=h�F{�K��XG=f��"��~�0�'E�ca���\��<H3���r#�?&������o������U�:#�k�>�d|h���(_�
���x�I�����A�v��?0!)�\����"X@@��t�0�L�	h��5f����,FD,
oG@YP2���1�{Gx C��ih�SY��A�o(I��X����)%�!d( d*L�T�3�sP%�n��!`�`k:�r����w?Q-@y%�
O,"���������.Lx$�������nq���:KJ�
Q��@e��R!HXc�	�#"R7I`����\9�:��5��CA�q@�������WZL�85i���K�H-��n����� ��]$~G%T�ei@o��
����K�C���/�z��k��B�V��+c� � ����|JiaH�DMt��I?����`�~P��@f�tM�[�y���������0���Sc��n%6�bU�	�xf�l��:��y���E{�]����o�T�����Kz&|-���OuG+�X4�
�$���R��1tSb�>��9+����%�ZO�jzX]~I����!�t�S���}�-(:���5e��Rp9�������6��@�	��&��X��N8�,��~��f�Qn+���NJ����g���1�����2K���8���<A-�1�W�^)e����m��h�$��2N �� �id�A��4��W�B��^8��X����.�x9SV���Cqi '���.��A�S^�`N�,e}���\��9#��&VH^��o�^@:��B�&/���d��ky���c�
{��`/��t����Ps_��B������Rf�vmu��\��v+������S#�ev�)�`8X����d��l��(�	�YnuZr����=�"i�W,G�Z_�����K���ol�����i���|��4���b���}�����Y��e�T������z��X�L��r)�w�L��^l��i�ma���9Ysf�9.`�e���4��XA�	(|�b`���(����
;�GX)�D�e
J�d��1����d�]�9=k�Nk"���@o�CF���[JOD��t�bX���J��T9R[6��������n��Q�o!�B�x7/��|%��k�3_O��Z��hs�	�"i�K��Ni���6]0)��Uc�R�n��H\����k��JA���e�*%m�]�X+W��;qV��(+����oAX�b�:�ZrS�����$�|�����k:�`��I��<5=4����mHj�Du9c^�;��<mH_�\�'�t����2W��RT���q�m�U{.iUtU
���.�U)����s����S�twdEz�����qU���:����V��<�oDS��%I�rT^NQw�J	*���Oy)o�r��$�2o��h}�S�/����r��R�)��zJJ���Hy9!��D��^�FtT+%\���%Lt��w$��v�
��>P$�y��>KG�����,��,E�������e�!�,��5���!��PE������	���!/;dE�����|�`�����������p:���=j6O�'����>��-�X-%�2��=R���3����7������p��FRf�H]c�7gH����=u�M?�,�5 �t�c@$�j0:@�����?P�k't�j>��9AG�{}����-.'/(��(�OA�4L�$@!#ym;�<�5���,�	�2i'�U��Y�V�4;��6����������z��?PKN�$L��@PK���P��7 0003-Parallel-Backup-Backend-Replication-commands.patchUT
��^-��^%��^ux��}�w�H����_Q����x�
=�` �!������b����H2!������6m��0o����@bK���u���*f��s���V���7>:��;�\��c��y������i5���m0}w!Z��|J�D��l�_A3O�q�M��;�9s��_!}�����^����������PM��_�d��n����N�i�-���f��_^���O����'oD���j~����}�?;������w>�^�7rbF8
f��8*�S/����+�����x�k��q ��+�d�V�rt����E���g��^���[t�d��T����B
w���������G�|��V�F�\�����r0�����_���������}���_l��:��������AO����r��'��Eq��� r�/n���vc���8�;���b���gF#��K��������;=��������z�:�H�'�������!N�r��C��;�$��`	'��,�<��^�����Ko����8vF��r.�`�F����i�����)�&���	o��co����[�)���?�>����������/{�������s@��h��s������Y}�:=��MW�n�A���N�t�}q�V�5�_�Zl`�)��;[��������m��x��b���5HhQ����o\p��X�����(�������������.O_}��������-.�iA�b>��2G��=t��t��m���zYD�hW���3B���Cg9���~p�	��'���j��E:v�r���ak_Ts2�����u����q{�+T�5���D'l�4�QM��� t��]o1���������#9vw��E#j�>5��.���/�T��G�;�x0�:�kw\GGMD"7$�Twj����������S.���D���^,���kv��L��������G�V�5q����k������h5���."�&=�ay6��/�V��l�`y�x8����s����V��1��60���L8��NY�E	�o��y���	�@d�i����r��������Z�^��������E-#A��p�tq�(��~���T�0@��D@���xkgg�Y�z��o���@����~��`�[<�i\�5�E|���>a������G����-�Z9Cr�����&�1����8��-F3g�XXC��^�������XE����o��ic������d�~�I��Ov�Sq�����y��B:��"���
���e�
l��x�3����ck�j��p�K�dm�B8�;%\0X�Y,��J��p(�����j�br;6'{����������N�]��?no���;��(�W�Sk�D� n���$Y[�n�.H9qc�e�\���^-=�������{��E5�b���C�K��~4�mp
Q�Y�w�8��-x7�#�^���3[��r5v'(��x6���qx�;/�:���7��7������ZM�*���%�;���7�����m�������W=�7.�
N/��{����~
x�A�v��\5���]��� ��q������;(@e�9Z����T�1��g���;z�%�n��I!%��z	�-,��6�2a0N.���2cABA@88����zxX���50`�|=���O���_�5��
�7����'=��R�a\�������<�&u�W�������{�DU��c��R���P���'b��.r�g��"�<Z_)���,���,�����Nd�e����u�+�#p�{����Bw�\yK��O�>U.%���a5��,�;�������������n �`�*�x���}�
�u��CY�x,�$�#����V�G��
��y�[P�i���j�
��wa=�9�o8�]����$�Q�LOu�H���M7C�k�A?����H���xz�xre^�q��3���%��j���g���Y�\��+ ����P<a����.���sPx`��8�
�sb��#X.H04*f���H�M��>O������Z�q�@t�J5UG
,H�PUBYC�[��Wb��Xa���d���������*��9����b|��o,�W44q�h���b��k�:m&[4�/PFY%��XJ���E�>X``)Y���4����B�������&SB�,a
�+��[�Y�<L'���&eK���C����vs}�_
����~l��������Ku����6��'n��do���SD9�;N���
��	��`��F��N����EQ����������<�J�\��
�h{�3 ���En����0�%�Z.�X&�O��
SP-Y�����	�m��rF�N<�{
[+������*�3@+'��ia���+UG*{�WAZ�P��R�7�]j�m����y*��%��X��b����R�7�3�`��z%E�k	F�Qz2�V����J^�/�#n����s�KET�����b�"���osM��A���'@8�@4��6���U7O��XeWw�&:C)��F/.]
A]��Q�pg����:���H�=�u����H��(%\����j�CQm��X{��7��g/_�Nr��ocRn���n��h
��V��e����,\�1,��XrU�O��`���rO��V��Q�EJ@�pz�8�8��2��)'����b2�*`ah�*VS�TT�[M	�u��:�>J������a���U4H��/��*N��@���~����9��F(�m�f5�N������fR���2v�D�<�����"q��?
�B��l��S�nFt}a��3w�����sT.�cHqz
�Oa�h3��|���|����3i�G�0��f�;��T�z}�hQ0�Xb;��A������|�w1��!�y��$&����$����c8��J(�*�~	�S�{9�b��Q���@���QnA��P6%5�A/P�ys��c|YM
���P�����J;�|�D*O�5U�'+�p�I�4'(����+[�G�g�"�,�~2�x��<��#*�;�������V�BeI(�co/Z��,�;�1��������-q��.�7�����3�P�9m��IA�����7���bh!�,����K���h�W�cK�k,��P�����VQ���������/�?�{�05q:�{h|�R.�%���nm��v�-�w�%`�ReF�C�P9�-���F�q)?���)����=���HV Y�9����#�D�u���YK��B��B(�jR�@D��E3�5|��g���(,4Do;;3�]��Pc��*�;��<a�T���8)��H� M>��R��K���4�z���mN���)���RP�=gl�j����?��"���6��i�j:D����NLO�U�r�m4Yh*�`f�H���$��C�#����V[���h)�L������5�a����3���j��A�$��������uX�tEu����:�Y�o���E�+����-�$��J��c�Qh��+*loS'
��M���!?�%�	i��iL8��f��(��s7�	���L^�h����8`(��V�0L���IH�cZF�.���;�$��h���lw������N�__]�������G��K8�#�j��R8xG���vU�����h~���h�k�w���]���Q���d>3��j;�91��Uqf� ���m3RD@,nDE�8z���9H���t�R��F_��	[z��S!�8_�;P/t����4h���X���,�Xf-�ldi�&,C�����n��8�8�i�%(����}r��u�'��}C�{���Cu*&,i�������u��	���(��N�kSK��R���IS��H�����*��R�����M��!]s_���F��:6�a�g���hO#pp
��LN|����A�<\^p��{t
���#���>j#����&�/�`dY�+3m��vK&�AEjX��i�����/*5L�N'��*!�Y�@}�������o��#Z�����>A4�{A����*Ytpy|��f���
���d�\d]/��J'�x���T7j'��W4���s
�
���F���4�d�#9��;@�a��$k����)�
D��[�m���dA����2�J��X8�'�(���,��
�)w2�!��&����\�*gh��!h��okC�������l�}��NGO�9j���Vw��R Y�.���.��&�+�)�+a	�f$P��*rn[��pPJ�z������(��v���N��?�
�������L��U�('�G Z�����0�N���z-������Xw7��!��Ah�d�vr�}�I����av��/{����b���]��'/{�������!�������/9>�2z�o[���m�(��0�`r0`�F�9�����0�%EH��83��x(m��n��c
7�\.��U7]6t�}�E�DaYK�|��^���^�\��9��,��T�v��P��d���lJ�!������N�Q"���V&� �c ��4��@g�[R�JLRT�YDQ�@��C��,7r��V����X<���
YDx�H���>�!3�};�v�%+���k����x�%�
v�>g*�#�0����W�\�{"���vU[lY���g
����~����Pz������+ ���_����� �g~���.+.GG�a�j�:��t��"��h�;���x �E���'����/M ��!d,�=%��lh ��A���sdO
X_1}��+g�8�4@����,���:��TG�sX�c��@(�������h�������ZY3j}���QC�+[g��f"���]��rr�Y�
��;�(e��GK��6*���&OIXq�<���i;�X-3�;����8��6�6�q�  p������Kp�r����X7�����bU��)�n���;Z{�Z�(91���S5V�����1xU�@c
(��W�}	TE��{�����*b�k,����3����%�(����!
�DE�w��\��}�
��D�/�pS��V)*����H�W��o{g��O�#`��s���[_���\)��)�u{�5E7/�hz����
U���������;�������q�0�`W�Z�+^��������([��U�m����>1i�7�km�'��V"o���'����o���JS
��c����
��&��-0������x$UL78�}\�����*�X�(M�h`��(��B��c��U�����a�6a�h��]/����b#Y�V�����������@���&��2�m�yG	�Bl=����(>6�#*��~�B�g�)<������lc��6������*���MF�/��&!�KI���	y������]�T��ygw"k�sDD�N
���x��9-/�r�(
�NT��$��;WU�.c�EqypH2�����wA���5�.�1r]m�=���>t2���m&&��$��n�e����LA��#g.�@�F�Nm����wC����������X
 5IE��G)`�A��b#��o9�nU ?G��1�jIG��|��4<Oy�����'�� �wc��isa�81�z��u��=�R���h�_�8V�����s��zzj����!~}����9�\1�Mm0�B33���y���8������y>d^��eO��(T������
%�j���
os&�I
p���lG���PUF�A���:Pa��C���^)�$�G��J+eV��t<Q��$8�����<S]��{%����n��i6�*VN7h��\���a�.�K��Pwue}E�.�K.����u+�Y����,Zl��A�g)�h���������E���J���cP��Snx0Y��d}4q��J��y�M�:p^J�3'S�UC�+��Vj�e$Q�@�<���2�(���	W��
�T�|:���w����y/=��1�Gb���W$�v�1��^���Q�-i�z��bP0[Y�b=2��������:����������]�q��|`^X��a;$����J��V���0w�`�4�5���ZJ@3'���H�DI��I&�6�(�X�!P����R����~�]��q���v���G��W�D:@�����:f����2$��h��&rU}q���Q0Z����I$:]S���g*FV���J�V���cC�r]%��o6��@u��x�
���{v�9����=�~�����B��}D8���P��\u��L� �g��ETI�'@	�T5�������nN
�7��F*Xu R�����jDdu���rRY����w���E�:������UU������SV��d/~�+�f`���e�nO������p;:A�r��Pn�M(bv���a�D������:�;D�h��>2���-f)��������x���<�������'����P��u�e��__������$}��!@��)���j��x8y.�4�$:A���a��������>&^��./0��R�J��R~A��\@���b�R�a��Z(�u�R�a��N���(^�viQ������
���������w�p4���2�V!��3����M��j�����4�y�T�q0����e��2s���$����+���f�_���GI���|u��>4�����������9����,C�&�����kM��(���";0r����4�%�Ta����h�=HG*�������2�"`7H)���6/�>�����uE��-<�@Ey�{CU�����Aa��N�]e��D'���+�k�
L���N
�V������������4 (�X,G�����i��
#�d�Mhe�*U�&�KH ��!%�������f���^^������
���P
�LZ�<L��%"d<:D���n�g���/��	�u�1yN��h�"�� ��o�IZs&���@��\�����n��XX!.k��Ozq���OZ{�����2L:��i��������"�!���{8}���"o>��u��n��7qLZ�[7n�"|�w�;h�4:wo*��n/|�������������y�[M�����R�(Y8j/V�H��MH��y���(�����Y���2:(1����1z��ca��-�Vl��j����w�WkS�qN.��M��'o:��=��#G+qm���E���)V}nF�lU����!$R;�J���,}>Q>��cYS9J�[<������u�����Z��	&�G��7�DYb�|4�G�`�1Lt�����c�?�dd�*`N��.��n���)��E~��B����--|lG4�+L��b����2@�\��D>��I�����Q��������L
�
�K�p�x����8-�
��������:�D���C7�gW,�8�j����gnnR)	k]W���Z���H��W9@1��a�����+u0��%�:��$1��$-q�S��[cekP����N�3���S�x
���b��9���4��PWvp���a�'��d�9�8�#|����E�FCx�I� i}��k���8����&g<z��Rl���ao�Q:,��N����*�DCi�z���������OOa}����oV���^;1���!Z��A���
oCOO�K`��xF9�r��XV�)�s����#[�u[�9h�����S����/>}

Q\ Yr��(f��d7_��#�����b��C�~D
R��xN�eD�T�}��2�|%b��Yn�R^jOR�0!�C�e�@yLe�HU�0
�t����&��fs`TK2���3`T�S�p�l"�����V�F��y42�oD6�oU���X3{���[�tB�s�WC��A{�����|�l��RN������M3c�7<JKIC���@����Pt3����J�$�D�������5a����Q�.yzA��Jy�~�l�LL(nIg��`L���o)�����,�{|�f�	z>X���j%#�����H6v��a�����	����
���J&��������j��	��s�tBq���h�����������5��fH
Gx�N�����tm,g&=,�``�G)4�����a����d�P�c����mfi�`��j}:P7*�`�xAS2�esS��0@�e��)S6H+�����Etl�
��/c-��'�^���E&���-7��=&{����7v�HK.d�vr�$w8h����ID��J�!�7�n����g�9�#���8���2���=�����/�>B$t���wM�e��X/�uT��S"C&���4��4�f��h��h����4��87��dAQt���8�3�����C�m����>yO�
�U��D�.��S��t��4�4�|�� �kj������9���D��/���r� `����u!R��v�Vb"�[�{}�{��t��c��������zD��N��'����(�9�S��,���@������.����T>>�@��-y��&��/���>c�0�t!4��j��Rfw��+?�.������w�*��AVl6�*�)��2'�O�{���hm$�*����`���9k���.��(R������F��S���x�	H��K]W�	X�OqV�H��=��F��w?["gh�I������]�yV7��Y�sc&�@>�tZ��p�{�6��Y���"��M�z�A8>���jp�|q<�����Csi��70�i���4J�=5����>'�M�N���j^2W��B�n�U
�X:�L$*����E)��[�vn�:�^�W�KJ�O+R��_�&:�X����W��d�y�D0V;f
�/�''���0�%�]QM�G��gR1Vi`V�����2O�=����i ��m$�H�z�Q6�t��T9-�Z;��>�`F����@b{���r��������4(�vh��\��c��N�����~Q�w�������T|f'��4�����w�p]����U�Y���GF))��$,L�R���W��S7��#���K6q���Hf�A���y���Rl�.��dwY:`��,.�P��_/���l��&)����\�B^>�|������Luy5�i@���N.�}������=�	������(�!��U�n����_�
2+�`��������O��{�X(���	7i�4JX��r�P���U'l��q7lQU��8�c(�Z&?�v��L��?��j@�/Sk�=��O��-�[�\�0D
�R{�r	�@6e55��"[�J�-�8���(��%���"`��y���iI��V��X�	(R���J��y���7��QL����)���>Ev�MA1w��dc�?$�+��N�$�ledM�F���� �P�����z���W�^�����.����#?y�imA�
����2��(jt,6��
o�U����r���n����-�c�u��]	Bm����pon7�U0��-~���c��m��F����l����(�����{a����E�|���M������h��/*���{z_��� j��<���?�f��3�=�w�t��jX}�5�8��6p���=��62�����
��!���Xs�`�7�bh3����%��@�C��$�K`������l��K�d����r.��
U�"�Y���d�������|7KL�_ ������[<2�EQ'���e�� �/e���NFw��
d��jH<�
�*���Q����0��p�}��q�E��o����K�I�'2}�!Fj�!3��8�����
s[{�����i��x�����)(U%�PM�r
Ho��X��������N��^f��Q�\��e�8���>�%P�x�
p�a|���A�gX������(�	���z;WJ[q%#K`$�i?_����^���L��(���*�)Z&���n?��	��rM���/&�)�[�>n{��|.�M�dz�e�z<V5�\����Ka�o�pI\r�K��%��}[q�O5�w��+"u���-n���^��SV��aR.��H^�^2��un�SN��\�[����e�@���+w��;wC
]r��5�p���/��
�s�2Xk_F�����L&��I_o0S�k��#ya����W�\-��T������Nk_{�?���[��j��7U�P�)w���L�dh��oA\��*�<g��\�����g��9"��b0�l��^������w�z��d=������90��^�9s4�l���XWw.�3�E�1l!}�+�����M�j���	�S������zF��V{�������;�Q8��le�J�J����3k���MJ�)�FL�:Ns��[���A��pt8�4�}�j6���r�^���r�Z��g�����a���}qh���(1zS��?��L_�+������&}~����b`=V��s
���~��_������4��W�F�nF%�M4�S����L��+�.�A="��#�y^�dN��S+U�x����?������B�B���#��8��R�F�����rQ��M7l+V���"1O��Gt�.B����8k�Hz�O����FD+�64U�K'����Z}�]L����z^�y������[/0�.��n�+;�3�T���(�(��<MQ���*�^�<+�cY<�+��S�r��D$����y
�23��`�����L&���61��a���$�_���<-����J�?����[����J>1��GQ���n����,(���\�V&s������3��#-���O�wu�||u����������DM��}xy<��Gcx�������<}��P0]�I�x}2�L1|�%QA>�J;�y�d+������L�%s^���=�\��8M�Mu/���(g$���b���'d��/�M6�TM��
6��7������:�}/o�O�u.�K�����Jx&$m���b����w���X���^(Q<�*�����90T>�v-���,C� �@�L1�|�����Au4`\������"�2[��A V�6�?c\�@Y7��!(t� )�H��u��i*��?�;���������=��B��xm/�*��q�x�L�-	H�$.���,{&������0c�(���O�[��+�m���e��4H���985����.W�m���)����!�[��P��@��6a�y' ����a������)U @���� ��Gb���]�zZ��R��bo�
L	��+0�^���'����m�V5��k��4{����FH������L�Co�@o�����.��t��������5�����-��-_�U>���-��X��e�%[���l�������KIM�{����Cn]S���+��x])���)E����X�_�!#���d�"S��%W����Ul���h�n�~x�	.�GV
���6�( �E���c�E�c���y�{��dX������Y����l��D~#Z@��sjW��D?Q��Ws�dq��������������)�^���YJ�v���1�S����]3��	�
�[�K�)�Wm^(��2,�v�/`e�Ez�}����?i]xH_�%���E=�F�����q_Z/.�Nk��Q�d�2�;�m){+{_�:������U�qF1z��y3*p��&�����L?�:����u����wpJhI!O�]7��P�dXf�qD��K��b�&vw�X�;~RD=w��D�k��L�)N.{x�e�����1]��?��=��������7���L1�]��C�a��E��gF����%���-96��(��;�)��
�:/�.(]����3>�����F����w�n���.r��^rSX^d*oNF�9<����e�C�-N�*$��8u|D��'_���"f�5o�+���D�	�2�4���,��.f�3Em3!�@��S�jS�,��^�z�5f ,m���fm}�S�l��k�]��7[�R����B<G��s��z����~e(�n\5�{G���h\� t���8��b��i*��9�(7��?��se�'����xF9�v��1��
���Qc�U\S��%�G,S5e�g����H
�Y������K�w��W@�����������S��\��C�D�1^�~��(��DI]L��������~�.���3�P�"3c�����G}�3?��|�l�p��,�������}���F���bxX�gF��0tn����=&�R���}�fuS�@Q�
�x ����z�b2�����)v1�'"zO�S��
��M����ou[��s�ht��fk���u���-n����2������\����v��]������/�'�lv��)��������[�4i����%s�\��W�YG)�f�=M��3"���&���b��&�����~K��g��e����kJT��s�c� u�9���F0�ujG6e�q���yeQN�nK%�W��$��r��<@�f]Ejr8�$��N�3+�7��_�hf
���I��rF�v��m5����s�w�u������,�E���"���EH����`q�"3�XPy��[%k�gb �p����"�_����������D�~.�/����f������M�:����l
��a�o(��.��F��h���3���z���S.�PK���;1��PK���P�( 0004-Parallel-Backup-pg_basebackup.patchUT
��^-��^%��^ux��=�[�F�?����;��6�8%[BH�.
d����?��AA��������<fF3z�&�����# ����3g�[o�p"����`k���m�76�;�nolt��Nw�����pkS�q�NEgG��=�Wt��N�-���7����	�������������5t^U�8������#�
-��n[tv{[��nG�������l��&=�����������i�&����}�����l*�bz�8�;�������w'n��"�vE�N}o�$�='�(�h���P��#�e5��w"�1��E<�N�(�0���p��|x�#X��$�s�
G�g�_�O��{{������8� �U��qK\4�����N�z�o��0�:���D�c1�|7c�2�=v��nO#x����@�����j��w����{'��������?�4
��b>��Y���!�1�bo��NT4n��6���������-T��������v�Z��C����\���oo���F�Om��;/���]~��W�#o<�-��`���A2X�]�F����bw������F���p��5�v{{sQ���UX������hv6�b
��#~��*��;/���+V�a�\En����x���}?M�#���_=��@C��#/���y��'=F0v���mC$wSw��E�D�a">S���.��[ i F��H<�8Sh�O~<��Nr�ZL�����T*�Y���}7���	��x��L����yY]����]���.���B��������9�<���h-/vp-/^4�;��y���	��'rA������sj,�9���U5MRC�}070�@��e����#Xk ����uT�~���p�
"����?��~��o/�����6�B��xB��� Ib"�����s�4�%���1p�k/�c8p�0�&���u�:�<p�����i&� 7�M�;F&���u��!�����q������}��ya=��o�����g����p&��/����g����)��&�J���0��t���L&�O������f��d�xH��.}��+8SQ����o�c�|�C�<r��I���4�	��������~��K��ic��GC}	#�WK�Ta�W*�>������[��+_D��+B�Gji���R@�<H:�N����$zKx���;�Li�����0�8
H��!��8�p|-�����[�[�w(� �p��pY��0v��5^��w}i����������B�c2K�/�M�7���]�x~�����������������������G�9�(�s
>��;*�����9o�3�>8=y��Z�?��QBZ�N������	����[�G��#F;��i@QO�S�������?�5�����K���O,������-�$�6��w;��d�rAHJ�3X���
�@��K�`�w��x���c:��nZ�%My����H�����j:/���wp� (��]�"�Uq�x�����>�

�lA,�n������|h	O���N�	w
L��t�e�z6���!
�w@c�/!9Z���@�,v���X������Q����;�&w�0������#�D�h0:��������v*�d��x
)R���=���)�<�z�|R�~vh���w��I�+E�Yb"aC�]`j � ��1�bN�0(!B�W����,�Q@�?��7J�����?�%�F�`��`����g���V�X=��U��\%W�$|(��������f6����nd����]��� ���|^��gIz����A�s�+P*���mhpL��r���
��f6��]��9}��`d�r�����C|��,��nf5�#�W�l_��Z������u7nBS-�s��N=�|��Xm�$����#:��xZ9�\n��
��
�Zl� �'�����q��)���	����$��f�>$f�D|��}��?�1G�����7i���)I���')b�|�|�dx���w8v75�w�.T�hE��/C���@Jj�"��	5�C�����5�aFh
�/af��E����fcy��N�#/��L+�l2�N�G������:r����^���5��{o����m��`��!+���5H�n0Ghc�������d��+�:"@�������M��	lwx�&������w�����vcd��N���������'�'�0�"�@fh�����Dx5���H��,����]��4j�.�b;����W��x��S@�oyD|�`snl� ���(�)��z���p��7`�����s<Riw������q�w�0w7v/6q�K�����*5�5�r0�G���4T��t�.qK��Ahg�t���-�-�0�3i��I[+h[{�i��`�
 '�
��MfCP�]��Qs��=��N��4H;?qQ�Q���>�x�u��T�&�.�yY�fM Q91�G�h}��_6��e���e�}NZ���V���k<A�TP��9Gn2�nMA��~5b+/e/z�'|�����g��Z��8>�G��/Y�2�i�`{��UH@h�I�E�JQ�����jw���i��7�W]�D���Z�F�t��5��[T���}*�����<��J�����n\zI��P�Dj��,.@����Oau rRt^��Z�oD���;!kE���u�P?R0�?��=��d���tfx6�d&d=��A��k��pxT,�A1�8����RM�*Z�|]����+��h��DD!����v�m���(�go���'D�8q�Ys���S�I��&����2��N9]O�I�r������d��v�'�+a���o�:�N.�7�oO���_
������|;<zS��
�L����8S�k�C� ��^��3��T�:��,��������=!\7�	(�����O/�>{�������Qlli~!Y5�%r(�!Z"�f��
"�$�R���L�M���
��m\0{M����P��_��o��Z���������x�i,n^������u����+u%r2��<Y�&E�f�X6��@�Z��5��++�g���\3���.�`���'j2�L8>%���=
���=��6�������#�3d������V����Y�*@?��H@�En�����^=�c#���M�]J�>�8��K5�&v`D���Y���9	a���������%4K�[#�L�����'	��myJ����,K�&�{�J��I�;^e(���E����!Rg(� �(�*�v��**\�|�]�����g'�HG-�GIv������b��Z�c6��Z&����&��b�-�P���0��ps�b��:@P�\G��Mr�u����xI�{���#�U��!�(���5��y�KX�`�G}�
&�]�����!��s���p�2��
~�����q�������>��N���������o��	��;����m��*(d���4���i�<���)��c��&%������������6�]I��q}�k��b���c���I�Y�����R4g-���|�BFc�0*�>ku���m
���l1i~�����L��uy&i�k{b��%�J`7_�����te��H	8r�<u�>+�g�_:�����������E=tv7w����>������b<I�H�F���!����0+�������,n�vF�7�a�ry�%��
�1�'�b}14i���6o��
i�{
g��aW7�����C}y-Ay	l���7�C�&��^�9Y��qap�0���f��U�x�`8(B�o���&�T��C�A����`v6yq�$��%��2=if��bJ�@�H�r�~�B��4~���z	0�##�O��P���T���K�DW�`��YIe>�
1���I�o6C�I���-M4����n6�x{���.?�-�dUO�����:f�ri+�����^�[�j]ii�2�L�S����W}�����"m��������NX�~��(��%j��A�~:�k���������Tz5n��3�	��@�t��"FG������og���k���f������$Ju�s!���������}��9`I��><�O�Ubu����&!�:W�C6��
	4����w��J��V����{{B�Ua��n;U���U�M��_\���T
F�NN?�]�������kn6�����*x������l����~��B�����t������xx����/`��/'�?V����2=���%�e:���L��}�O�o�l��N�����p���^�<`������l�����d�;��h���p�&_\��_����
]
���S�,�W����O3��
9��#����~gF��+C����R6��.�$�`xP�>;����*��}M�1��!]��VH?�P�_7��=1��j����<<��Od
����{wr�&5�^�����<����b���Q�����v���u���R���5�y�F����n5�d��x:[Q�)��_a�c2�	*Z�xK�X��p�[�&��&u�3���7r,���ES���Y�����n��w< �����]j��")���2���]|�|�m��������TR��aVQ��#��"�d��g?��A�FW3�Ur��Y�utEzl1�������V��U�Fr�V���Y[��8���w������+=����������E���L"��<��I7-i*����3X�2$1�x�x��J���~�i���6���<������GO����YP�$�}�a(MQ�������|��Rx�{�L���`C�Jxkk���gy��d���E��T2q�Lkl
BC�t-s��\�{�)d��a8�L��]�e��$��pp}�6P�&�%34�P�v���UdM�JoL�����Q8���������e&�P�1<�:~O�rr��PY�,�&m���
�[3�n�&�X+n��Y'sQ�T����!�ht����1����!�L'������C��A�$��a�A�ki2#�����}F Z��hD4�1�)��wM	U���t-Y]	��O�����~i*F��$+��mo���Zm�6�8��X>m���R�a<q9X~p���[��L��{kct����V<������IJ��#W��o:t<��Sg�D�������thK�r�\X�JI����D����W��Z%s-*It�
����TJh>HJPGu�����q�8�����3�*��f����`*hM���vJ@������R�V
�E��pz�j8�Q�^��4�$TC�����{���pK}D�4����3��7��fH4����_>Y�i|����s�#��]�������O��m\f.�b�}$%� ��t����K�D\f��J2.���)YB����<��i�Y���g��i�2���~�����o�o�/��d��?�]�1��GS�E�A���K��"�5}$�IE����G���K�p��ucb������T��������e�c�P7?����c6����ON���3
ay��'g�Xl����������t>�P�7|�������#-2)�S�M����Ki���(m�|e�2�d��6��e3�����z�}E\��f�������i��r0��
�2����>��(�+�F�u��2��FL���3P��OI~:��C��%10k��riW�k�9�Rv��701����F��|0'
�[m��G_.�9��P�*`Z�g>Xp���������Q���}�[�T�kr�Mq��\�Yi�O�����sOg��Ll��p�����o�m��7����.��u�6v��t�iN�yR��f�x�6�S�<�&}�����8���7����w~������{��������������n?�|>���u=���z)��0}������>U���mv��4����kC�?������]����*C k����-�b�����n���]`k{llI}�����S�,xr�Bd��1��aK���	��s����uw�;�����/
�^�t��W��4
�;]���%�����K�?h���\��pbYa)fC��-��U�+h�i�q3���d_O4�*�5�hX��Rdu+Ugau��V��?�0���t�D][��0���9��+�������t�(������}�O�9����w?��]^����fc��Ew���.��t��h?��P!�m�]\�)p�<71���T��N�*�V��d����0���
2}1��z\�u �ne$Wj1D�\q�3\���r���0t,�A��#�o�XFz��-��Nr���i#�@�;:-��]F�3�b~XJ�D_��b��!�9��5��#h�9�|A
��L���������5YH����6z�4���U�	i�F����������j����L���%+tp[��6a]��u�%����>I�GV��0��F@���&�hY���3� ]�3X��P�Kz�������z2����Ryy�A����J2����s�JjOGu9�hE9G���GI�L�(B�b(���(���yD�m�ugS�*�������
� �q��,I��	�Gc��Ea�9e#�s��	� +a�d$q�ZL�����J@��jI��X�Gf@A?�hs�K�&tm�2`�G��F����18��;�_'��]�B2A\�Ihk����I*k��?�i�����<'�;�K���AO���D����Q��x���v5�"�(;�������',hb���cE
s�Pi2�ejv����;4n���Q1&��'_��t���$4�y�Q���\���`��A�
��d'�^@�� *B��MJzIh�z��J\%V�Q�\-Gus�0JK(��@�2;Y��A����t~B��\�9}��dF����e7h����2���&Ntc��n���PVW�E
�������*�'�+a�����:�_�-��R���Lf\��7��c��]Ig�}&5�)%uISm��[)t1�<7u��;��a3WU$*Hh�Y0��xy������)K���9��~�(tF����,������qH��!�+�
��PrrY�������>���`V��FyL�/X�:��$����!}v_�l����n��)��������gPB�'�����j�Ny���J�*>:)�4+��.�mI��Dx����uw����m�Sr�q���+���t��n�j�Q�__��)�(Jc���(�Q5D�
�A��)������X�����/h)i�M�Q;j�z�C�hn1^�zOz;\P�������gP2P������4�SZ����w����\j�sa?�I)+�o����%�~�%�G��l9����	QQ��A�0Pf�F����IO��`1�t$�&[��HSw���)��*=2]�eb�:
��m�v�=o��������C������$���[z��.k�1&Z�9�M\a�����U�lft����pZCL�6l����-j.���\��;�}���:m�Sd��W>M���R�U����-a�Y��
M�8�v*VX�0oP�>�'�lR��sK{�v.�*�2�B*�H�(c�q+��D�Q�;Wm���a�E���T�eE���m�\H��+�Ki��b�4k���|g�1mp���h`0��t�L+��5O��le�N��F���S��}8$��8�K�`�������j*�����j>��R�H��Nx'�G+��|�d�e��t�c>��&J�u
�Oi0�`������pZK
Ny�F�o��{�E�1��	lyX����}u�����W�7�� :�uU�9���~)�0�dN`!�$E��?Z:��)-N���d�i��s��B�
�LX�A~��<$��3��	y��!��
#:i��0���m=
Q��z����(�jiJ�H�l����6K�g���K�B�L%#g�5mY^����������$2��_��(�}3�}s9�.�}��3��u
7�[�������a&Vi��^�20R?2��*��r�jXo��+�M�=�V)�����U5���s�TA�d������
�
y-<���D����,I4e�2ZI���
�>1C1�I����KY8�E�	���qC���OL�����:F�+��?�a���4<����lD�D�!F��&[��>i�6�(U��S���75>7�]~.3���6QW5?G5����g���GA&(����r��8?���dW�|�*����^nX�t�8�g}�R_n�����l2J��9���G�u���J_�P*�Q9�
���dp�l�&��1�[�� U�E ��Y�Rz�d�{��������g���?#���z����_�~)�eA��b1���Jcs=�����w#RK���9x��TL	����0�k
�m���Br��8�X�g�9�X[�5�t�������k|s,6�6f�/�����1�������|%�
Z���e;d��+�^�-�!�Fzk������9|����a
_u��Y�V3��
�%���]��4���i=����_������,S���hK9��R��4��;f�'cI}P�T������D��\��cE&�Dja���=DdP��~�n������'/�>X�e�2d�5����t��kHq��{I�m9/���X�d�E�cV��8�4s[fo���K���/��9f��Y����*TxE����<�p�'^��_�$����L��i_�)e _�N|Mt���Qu��<��J�[-�����q����D��q[�Q ?���a���?����-���%}�3#M[������C�h��m8�52�on��D����e`J�S�&+L�����:%�Y9���e>�i|���H���}��c�?�����y����a{��f�X~��}��^���7�I�&EW�� j�uF��z�*�g�w�
dG4�Z���>�
T��]R����3<���f}���j��o�:M.a/Gf����b�|DPDc:��i_[���U#�K��GX?�����{|l���<�E��$m���2����s�R���h��[����x����#v��d�J`l��p�}�L8CJ����m�*
�k6�q�����7D~?f��iRRv�����,W}~��n�yA��x�r442&M�:�i�+��k�_�L,P���*���R�}s�2�=M�d��=Qt���s��d
�	��"��������x^���{�M��\��]y�y�u���0{�a���>�E!���G���!\�(p��g����nn�ot�w7V�/2��7-$��qM��;+�8\�7��%H)8l��Ot�����<��i���<@�2����)h$������.�C��7��q�a/�
���,�5��Fr��r~�������j?��hWzA�*f*20�yA�n��E~f�#���U>6���Y*��hD�	 Q����eoD�V�e��Q������8�����h�9����c��_f.�2'�>a��#Kj��V�Lz��������uU�;p��eh�,8�3��J�rj���i��{M��fd�x;�Lj?��?;M��g�D�F��u������B||x�3��-2^K�`J=Z��Fk��b;�}!�;�a����{��~z���)�]PD�t�����
���OS���#����6��_&�i>7 $���C�����6�,��Wp�6�.H]z\�n��"G�zm�Sm�&c�P"��%�� f�W��7��.������oU��R�O�r!)	��,�*:}�c�,��bQA)�����!����-��a68rI�{%YB!.lY}#5��:@(b�Bhk
R]0��G���Z���k�xE/-y%�b�~
~NW�0���#�>��/Q�<���
���hey�����a).b�zP8����+��4�vl��s�E.�"���*FS6X���;����<�N.C)����6��I��D��CZ�]+�SB���;*R��?�d�P��R�#e�jy�4�{�D�.~��$Jyy[Q�/-�&J�*a��������,'~.��z����r�m5�G�jH�c�NA�3~������5wIL�I=q������l�{�j��:�(�^�9�v�nW�����Y�~��Z����>��fy+�����y_m6E���n�:��?��������n����PK��	��'�PK���P�G# 0005-parallel-backup-testcase.patchUT
��^-��^%��^ux��<iW�H�����vr����@d�	!��<COf^Y*�dIQ�,������[U�el��:	Z�n�}�R��������j0��mk���o��6G|�c��z5~�������=�}�=v���f��.�a�^�_;0�l_8c6�������p�	�����L'~�2��>��eso��_�3+�6��nm�^���V�W������h�}9��<�������7�����e#�����"."��Vk��5��t�Q���3��1��r��'v�%?����l��Sc}6v\����M��A�O�0r|O4�[5f�Ha3��������d"��#��f�~�Z�v�c�nO����G�`����y�FR�"��x6��?���=���lq{��6��zs������w�������2�����\p&����7���=��u{pc�+�;us4����e<s�����H_�N��[���f4�Q�,
y����$����]�~�8�����'?��x���e;[�����$4g�����_5���r�Cj��(? ]3@m8P1��>�c�#>�P����U��!Jx�Mxd��
�m6f��)0���#6����	��C�����4HU�
���o�i��9w#�p��M�R�������='rL���3B�����<p�Dr��Q�������Lj��(4��_��mFf��r�J�g��
���"2CT�7��@�X��;C3D=���'���+�_r���Q[_�>c��`��1f��������>��g0%�F����cf!��9��;�=��� ���n��a7S��2tj��#�s�G�����9�����k�c).���:�up�M?�CV�L<Y(6X�����k}�J&u���������~Xo���A�xQ��i!�X��)��{�?.�^3$��W>�Y�T����}�� k#%{��n"���
?�;.CX��7��_%Z�
���v�Z������pA���2�6���(���,�=���V"���m��r
T�.7�`��M���3v C��
��1���G�Gwd�S0$0
�h9�.!��F�!��5�qd	���j��\��fg>c~����g\6�s���#_�����@�l#�
T��.\���6Q��n#`N�������B�^C�'�7a���J�&�3�]��$9����.G��L�����E�%���0P������u
d~x��3�6c/��1A���V|c�DA�M�0��kH�����������r����}P����!Ra�����B�����/�!v����	��14S
��!����P�D`Z���K���G>1��f���{���B��*��X�@�Jq�|Z���������?��_i/�S�|�6��PAS62q���bRp9�!n�Y�������'�3p�6�CC����<��}���4��G��L��+(p� �^c<�.�s#.B*�8��tqxrxp��o
��csXI��HV� �+�|�;�#�
B_����p����qzr����v�����!+�x��c���Jyp��=�sq�/]U���.��	�CJ4���Ff�F�^���yZ���l�������[GD���Sz�3��������D�P0��x�.)@��!V�����O����W�u�P�f��!�"�"�y��:��Hi���Hdy��0z��&�>6�Pr���X2�>�;Dr��;"*����]D;;;�exAW�>�w���|!o����`�}Pq%�A
QMIi�����& ���O����d���������p.e��<�,�k��b ��j��2���b���
�E���\�>�h��px��ba*�Zv�$���4a�T����������J��+'`�W8�m��gIU�>�<��@ U&
x�a.c��>��
_HD��*�#�8���7Xo���_�z-��Z�&�2�4>����<���`�a4�B �Y�f��#q�ra����LL���<��4��&�[-)>9u��:�j��RTi����D<H�b�r�3��y����������'�����N���������+�`Xok#8^�GP�y"�3�Z�Y��]9~��u+��xV*b��}I\��\�?���2m�P CH�@**���c����$�HZ:�������n���\�z�Q���S�X��#jpU��{��SV��I�D<�@I�.Wxe���va!M]0�B\I�B�	?���w��i�*���s��(q^�1�|��%j�b�CO��/����)�YC2.r��2
�;�$����O���`8X.�KIZ���l2q��ZR��A���$�i�3Tu���(���.x�f33#e*$Y�c�}_"������.�Q��})�z���X����Tw�����W���WBf�/��_��B���D�5v3H����������&�����c�#��s,V�*������_�V�j;���b�D���B�'��u�t�rO��sq7s�Jt���s�5"6���~���d<I�;%����07]��C`�a�tf�lL�T��jK�?�ZX�: ����@|�n�$��qg�*��f�`;F�Pv<������/��-4�J#ShHr����c��@����1��z�'�<oQ����2�^uN�}#V
V���r��������R�hZPq�p-��N:��A�}/��g��6�P�zE'�p`e���N8�.��a`
` 7&T9��p3q�z����`��d�-N�����6`�~��s���{���Z��;;�I�����ufRk1AT��;t
aV��'i&�B�C�<�&~:��\X}��@�f���o�t�8�?8dj:;9;��k���+4�P�_m��>k���+Y�M=��_��|��N�B���,�����/+���|�Q�G(�U�-����$��,A4U�U�d�QDZ��.K�f:���eXZ~A���!GR�(-�1R������ex�����$j	_��v���1}��:��@����B��k���C����
?�i+T�k���M��^e�������ZI�s�>"
����S?�;��N#p�Ba�D�>�P[���y��g������V�2?_6A/`(�^c�R�[��Qng.E��[O�������P�����X��.�����8�N���Roaa;\���`�(�)5��9�L�>7�r#�lgCa���i����{��D-�NQ�c/R?l�]F:��h����H�	�"����?R�l���5�d+t���Lr�V5����:�f����%���p]���u�|�����k����$��g�,91#R��Jq)��+6D�V.�_��I,_��\Wqu�]l,������Q3�-�m�Y���������x�iE1�N���$GT��5Mj@Z�O�tzf %,}b�-	��@�� RO�*J��GC��bJwn��V��d�\�q������-I����szV�0<;Og�K���I��r��%������E�$W�<%l�\)l�J��Fn�.�UN��=& G������ -�J��J��c�7P��P����������a��/`y��������a�l�
a�=���bx"RFw�����F�y�w�.
LOb���FJ���,����zr[pI9�w�
k#��,t#�~Bgf�g���}<v�y�S�\�E����I�qNp���Ai,��YVn�:�n;O+����������#f����/���~�����������3���{]������
A��7���z������62��F�2��:���>��4�W%[$dX��=H��D��S�oY�[~��ZfkR��|��%f����!�h{~����/�
�E��!���J���x�]H��0�K��"Z�������'�>�K'o������~����x�@,;�5"(c�����.����qS��(�4�rx}Kq(l_�����"C�T�����=F�])�wD������5i��Y�kP�t4<�������?�~8<L�����c�XI����i!��seY�"<��m���0�H8vrq��x�qJ�����q�C
�����K����O2!���?�]rL�����ZG_�|��1��T��M���:�����8?�+d�G�I�i����}<S-@-�'�.���������j���
v�u��e����'�%"M[�
�,�������6P� ��G���^W�Q����������U����/2�k����������L��H�$�.��%�n#]��"k��9�ry}���c%b��0]��gg���L�M}���|@�X��������R�����~�|G�chkM���C������Oe�0����Me4�N��j��B����_�VLv|zy���d/�q<�Gg��h�7���s��C�x��O.��O�8�dM���i��3C�G_���0�^�6��@_���
$�2$
�H9�Rr���AL�!����l�M��$���[WL8j1�����@�`S�����K(m2>�l�����5���
����FJ4o��z�������6�s�s�(���z����hN����#K�~m���K���vk����95E_=���-���������u�������c�E�y�e9c�E1rs�+J;;O����3G�Ll�,p,1j9���!�o%*�=�-6���Ie�#tb%E��E�Dk��;�-u���1��^��q����)��R��J���U���<}��PJ�p���t^�.R����w��T��z�zD�j@{�[E}����Jo#�������Q��q>�p�xM��O��=O�������&�����������(b���}UP�G9�����df�M��7������fM��j��`��g��Oyt�v��U��PK��\��GPK���PrK( 0006-parallel-backup-documentation.patchUT
��^-��^%��^ux��\�R#9���O��� �6�1��G��a�]��zg.66�J�5T�jJ*���>�����\fJUV��|5�;qKt�V�R���I>�T�����pkk��w����z7�L���V8����`{w{�=�����T��E�����{O���������{6�r���,�	��������gr:��n��[����Q&��?dGb=���7x��go{��^�<�*����ttq�#��l�{a)�x���yp����B��H7R%�V��i�{�:���8�L3eT��.�b����p{����S����f:�s-������0z�&2�3�LE�f��m&-2dM���h�B9��Ng*
��w�9����LBq���x0�����nw�w��A?����~��3�$���K�{���g����v{�������7/f�*���� �!��e"�d@�`�
��x�����D�����Hj#������k��;��l��z���[z�3"���"x,a��btvq�qt����H��k����Y9�d���d1��!�<|�����E��������H�ht~��i����������	3���������ae�
!���m.U�r����x����U����t_�h�2if��	��(�r�L�4VUN����b�����ba������D�,�f�|�Zd�(�W`ml�2��~�2�2�t"�]2���"u�4��4Zki����%��ZXV�m6�����"�F�,���	ejB/�uOX�@R3��@N$/`����������q#����pJ�\��
��\z���P)�P��<��A�fHB�����N�E�Dn��|{���y%����it��:�J��;�i�fs��<K�T���Y��E�r���1J��Sz&~���A<��S%���y<�=u�'2���nf�L$6�Lb~+�<f<Vyb�2Cn83O�Dd�x�9����BIX"�IO�.#�����3��+���@�'��
}q����Qs'���G9����X0PM�����T��2��	�5d�G�P�I�]���]}d(�|:c}��G�.� ���u�pd,�Z��[�[0�(�3�(��5����q��������[`=>��~��d�I��oV�>��n�.H�� ��@t�x*�=�-B5Nd�&�i������H9�`8��O�3\42*�����Lc"�s��(��[u(���9�yt�RX3��'�9�1]�p�\j`�2�b���h�G���@]"�����U��~Q�&f�D��G
:i7��A6�MH&� �k�+����H�Q��d
��Fj���a�)ME0I]��QU����������� �v�^�c
@�=�*K�o=07`>�<���P2���
f�e1���:�n�e��b-7�G	�}�(�������	#a�@��eG01��)�v,����'0�k�r
�#�����a�PLx��.�5[K��b��/O�����	���e�l��g*�BTO�f���J�/���I���� ���hn��2�(\q�bvk���?�|�CU�����������d�
�F����l��@�?���
�������?W����*�*�z���5��B�z����]�.�EJ����i�h0x�������8���*��~%����/%����@w
�A�&��������d�17�"l��N#�@e�yB@q*��?Hf�C����X�6�
�+�x�Z�%{���d�� 1Qy�R��c�0Z��a��2'�(���F�xP���������<:n�4����-�'2�zvGe�<�n}�O���������sd)3T2r5%xD�Ub%)�OG�)�!�i�Z��3p
�?�5���@0K(�Cy��n�
�>-���ZA4��Xp��������0�����7.G����������l��PD1�b��H ��K1�:0A,b��1���8���,���
�����P�7�z������|��fy�a��uHV&|Y���`�<�1�������B'e=��``j���R�����*�oD��M�0|nh��4@p]�|Cy����C/�M��'�P)\�>�������	N���pvx~��4Z�2��5���[]y�CA+�TFq�n��L����2�e!}k�T&�1���;���%�8����Tef <a8�&h����r-S��c;EY6����]�������W��qN=Jy�g��Mx�@6�A�c,U"����|��M$y����"�)���,D�$ Q��U
M�����S�&���r:3���9,o��Q~���L���a���	+
	�pr��K���H�7kS���~�����%s6��V���R�<L�����po�����X.$�TK�	�HM����+��M3P��f@�
x57�U��a�@=���`�2�9Qn�6����M��T��������'K��h�E�o�nKN�(����M���gA�J���a�o����6�
9��/�:���+Nr���ig� �e�F�?B����ea�.�!�	�9��3K2Y�|�t|r�<A*,KH&���$�$ ��Ri0���~�z�72�{��/�\-�-���F�J���������I���O�M���1>����.<�3@���R�eC�R�������yp�IZOu}�`�M��HX��S3'�W��Z����=�5t�5��Z���&���{�����u0\���Uj?d>_�C�}9x'dG��N�v('�)�������ZE��f�(�jge���X�rA���h�uO*������l�

���>�.F�TP��z�L5�V�������DfK�y��;�K�{H�PHP�B�G>������a�W��!l���	hn�h�rX�x~�U��gD�B�Mi�3���j�p{���m�5��I�+��
�	�������'Q���y<V�������x����+��3�b+�lU6f[�+�0<���J��X?���p*ym���]��qbv����������|���Z��U���
f��`�+ ����Z���[�6,���,�0���	��������O�6���iFKEx����m��� E���1��,@���"<
�T�,Bl
��A�"��X+7������YUj��M;���6Y���L��wf�'*�t�����4Z�M�_��S50J;(K
#6����d~�K��T~w���g�E�E]=<���\{,�2I�g�h[����-�4q��Z^%�E��wT�O���$R�)���������Q���������{�`�$Ozj���
��'`�W�{�Ul���{�mw@u���g	]{Bu�'k�������FxJQ�x�_�`Q�����
]{|Ap%�tK��f��
�S��d�NG�m�.�$����d�{�n���\}q���D�bWtP�A�������H����)eU��h���z�*�X'f���e�4fu|>�M��g(�78yQ����N�r������O?��K����X
�f��-��X.��`�#EL�u�Va��z)Y���7����~�k8Co[I\�4�M�^����p��6�8�iP�En���u���k���n���eM�O����
<��H����lz<�����+��t����L�z���g
V(h��x�������Q����! `�A�\���!�s9Z��"��,F1/�����fh��~�8�fc�0�����U��v���G�?�Sw�=y���8����,�:���K��s/��v�������?���#�Y2�{���������o�zQ���l��/R~���r��!�G�cp��
�C�gT:?+FZ��e��7tJo���Mr�c���7�����.�A�/���"\���������t�$s�%�����kQ�r������/x�|���z�w���
�?��a���uY����h����(2B���
�H/x�M�%N�E1��X�������!�!��
����.�M��y[����2pR&�z��g������r���|�x�L��������+�O<��>��b`�����#��+�^�������g2�^.f������������)z������Xz~q?��g_�b�mN��<�]�������%"�URX�]'+�Je��Q��Oz�@�B�nw{g������}�������5(+F������P��`��k�V������PO��f�Y���k���}h����=Y3����j�?<���Y��E����7��?����S�j���7�,��=�{i#�~E�{��G�����E"�u�?��[�_��LD`��T0�e���dqI����P`P�\w��b�}�2�C�������+���M�4���wG��n#���u0����_��u~�LG�M��(��UHA����������F�}O�uB�F������c��n�;�]�h�(�Vsq�;\��2~6�^zV\�������g��w�~����l�Z�PK� G��rKPK���P}? 0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
��^-��^%��^ux��Y�S�F�Y�+6tBl,��6�SBLJK�}��mFs�N�������6�������mH��2��:����>����(Q��v{t�[R��������V������VK_�g������Vk��A��r*G(f�0�9���|h&���8�G����+E&w�Z�6���Y$(��g{����nA7oU.�����v���������tZ_�S��L2�C�F�f��@��^�n��<�0����1
m��]���@ec�|����< E�J��hT M��aoNG�P�r(��|�����+8;�h���_�H�7��N�t!�S��L����w����#�Z���A��(�@l�L����U�������iy��a������~�����Z��-��Kw��������h;;v�u�t��Ci&���<���:.Q�%���^�������
��21�d:�cx*�3|Yiln�y8�OM&yz�7��1�B���p'"H�'CDL��4���J��0@[p}|�iW����)
�������cC�y��2F�U���"�#��8���F�4���#=a����
��p/�����Z�^b�s�_/��!�CKp5��8�x��JC��@%p?�0� '����	0���(���6��;Q���gZa��&�oYp,Rw>�b���f�nU��x����O��6x}yoe���>���3g)���$Gy"�%Bm��\+qT�����2��~����Q���������=�����G��{�1G:� ��7v'��E�)��LT=��rb���ks������I�S�q�L%�L]T�>��4�V��+
=UMs�����2�j�zy���Dfy�i���X�V��o���n�|�"��D��`�����@����{t2?LIg�kI%�:�%�0W�C=Rx.�cs���
8�1@c_��6�<)����)�$�2��	�&|���c��k���;�X��dJN�|hV���N�y�&�0�P�o�����L�w�z"��<�)���?���E&��b�a�Z���&�m�(�Up����Q��%��
������r����@/���d�O�-
�B�r��n�]L��L�`��0�Q<������B}k�k;9��]\�tQ-�|*9���8���,��(��Mx4�Z�F���+����@��3��g4m�e,�i:��Q�-S�ep,��Q�����	���s1N���HfTMM^H�$���,5b�R��-���zp�>�>��\�U�Q����\UM:h}��xGo?��������
-(�������	DJ)�}/���:8Z��4R��R��dM\�#�dYX\$�e��{o�O��?,k����2���Ee�PMo�jR���9[�����eZ���FQb#�$*��a�F��*�
 ���=��v��d�H�8l
���Ld�'�`~����m��m
M����H���>�_��T$X	�%a&bL*QJ���S�ko�?��f��
;<��5s�NA��.cj0k��=`�|�	N]�XN�+�qB��@�B&T�h�s?a�Y���&E?��	���z�}��������[Xh���bf+J$��&�BL)Q���G�A{��Y��cy��<��D<`��K����I�tu�v&;�[�kJ�.��������S�b�a����1��\b3�3E� ��&��X���D�z'�.��9W�cLU��-�UZ�o��oj�fk���[��z����"����mg��N������>��:V�E��bL`v����ft=�0�,=��mk�ZE�&-pE���e�l�q
iMN�����6��#TU�&If>�)KzHC�<BV�W^���d�����oo5i�����*���3��������O���989�Lrv�������9b��N�^#��9UN��y�`��C��U��*`�
�J�S�,gbA���qk@��4�0cmc��eB�����%y��*�$�(\�Z��PvEM�v��Ua�	�����k��0����}�E.��� ���.M��ZD8�����U(m�'�>q��d�cF��CO&�����\f��P�B-K��h)����c��d�|B�`��.5��E�r�&b�&��T9��[���~�gw����!���K�}�����f%!x����8.���t@�f
i�^W���5L�,A�����u�< �C�M����[�\�[�����;]�$����-3������e�,��ydJ���h�HM���L%�S|����hf&��*O�/���L�Fac�us{�C9B����}U�������Fm9����yM~�u�Z�C��?��.Ft��km�"'������
��l�6^�9�w�8(9J��2�t�����.�"��6%n������y�f����r����;����-�Rp<^���=����m ��^�~�f�f��r����^�����p������g�����^�.�:�\7{|�����j����������o�TX�xTO��:�D���
��y'j��C��F�'��4���Urp�4*uQ��V���0��Y�rw��������������w��j;T�d� 
�@U���#������S�#�����I��b(=����eI$�y�G�^��j��NX|�*���R�,�r�.���)�D�.W�tf����M��/������m��r�R�\e�a����f%rg�,0�7NQl�f��wa�o�*��SL��F�k�8B��K!�{��Bzf��)��3��L�(s3E��Y[{N<���$� �D�%�w������N��%���l��S����D?�@�V�z�*f*�+#�VD9v�|=�oE�������F]���_}��,�y����X6����Y��Hz�>��;�W]my]�����nQ��FX�qO�������+�)��n#j`��3�����=2����n�@�(L�C����0'S\��#�\"�E���W�?�~<�����
��G���W�N.d'F�����{����������m
��B��'���R�`�,���������b8V�(?��3��,B��<�X><K	�������x�R3�����*LIy�)6������%�V ���>�/�K��]�@��-��?�����A}Y���[�T��DjBx�����B���v���t�z0���Oa�p��Z��?PK���'G}PK���P�= 0008-added-windows-platform-support-for-parallel-backup.patchUT
��^-��^%��^ux��Yyw�H�}���o,n���=���a�YC���^Kj@��I��n��oU�@�2�/1juuu���n�=w��L;fKW��3nt�Z�fu�n6�f�^W�m�;:�����(���5EQ�kds]���=�/��1T<1x;�f��[1��t�~�/A���C5����>o6��4E������_���{P�UU�0��&<Y��>���Y0u�������,��l���3�a��HR�\�����n9��L������-{�S��}���6��gF���&,�gfE����M�}B>����9d>�qM�dA���_]��F�����W�mV�����7����3g�M�B�
��s/�\�������6������P������V�y��$0P����������w�K�Lk:�ryf��/�_�@������n�����4+�P��i7�f$E��{I����{���V�E��!���w���9?@U���+�x������W\	��5���|"������}���K~=���\���l��g${�>!��=x+�;h��K��s�N#��z�(J4z���e0*g�7�'2i��(�W��P�-}�{f4)�y3�d_*��q�D�������v{������]�7�h�~'��*"I��1���e�}{"����F=��hG��&����dwm3It��?�?�&��b7���TL��J�������V��i���J��ZP��j�����r{���Z�~0���Mye�����55�����a_����w��q��?�G2�y0��h���"�+����S;��T��4�U���Z9���K���l�����0�Zh���T�l6K�J�����7�Ob�#��>�d	��]�t+-�S�cn93Q6`J�B0�Q�Q�
�R�v�����7-W�#��Cd�����m0L��������2��HJ�ECQqJ��4���``�4���SDb��,`�xN	��]�ok�!#�'(W�!����("��Nc�E�9I��Gt��*�����8�������3*�����Z�����S~'"}�L](�Qo�3bI�r�\.G:����c�=�94���9�m��3�1Sf~d�E��'3sY�b����J"��)Ja��pm�5�$"�L�"������>��N��y�3�)|�##���._2# �L+��1�����E��>�@N��6�)�O��Q�Z����~&��j�������X��E�R�/QG�PV���G*�lnZ,����`���Z,m�@Hb"V2y���.�=����<�e��K�!����pc�:r����v��n<w������h2�������$8�>b���������� �>��_a��[�����eb��?��+���V�D�
L����r|k� �hV��l���kZ��[9�'�7�g(��)�6^��)��`^�D�Vv�tb�b��p���kH����!�1���B�}�S�;B���B�hK��5�ur<HNz*�V��\�M�w2�,��@��Cd����4&�G�q�s��]�����l�O1:e(�SFD�i	�Bd=���1x2m�"������<h:��b;�M&�(Q�����C�$����fn����mRf������X�(�ZP�C.r�����������[XN�$��W�rRaC:�^.���}c��cU��w�m�X�X��`����x|F��]o����N\T�LY����z��/o�sw0��Q��&���W3]�����9?d~��<����n5�?�W.�U5N[A��=���{![JL�Q���."C�+���������?���ol�Gf��N@a�bv�E����-a3yLt������X�B�D��[���=6~��P����P�g�|�"���/�#C*M����b�c�\&��!r!��h�����)U��t�A�V�Q"�dF�!G4�A���HZV�&��ug�I���v�@�%�����\���T��]������{,��H,����uaj���"	2)�!w+����~�?0{������=��6�)���&��2l����1e��������'�u{�n;Y�!�/c�������2(D�����\��h�un�yE���:�J��2Cm1�vV�������d������'���tXj�EH�Q�����kk������g����P��y)��%'Z?�VF�m�B���X.�V�!�j:�/��H3�Q������Gv#qN�%�8��@��^�g���Fl�h1D>�cp�L�k�q�>u�t�q����mC��a��EKS�������Kn�g����(���������B$gn�l�����������U�/B$���n*fA���z�Cjqq�)5�Xo�:t���P�A�U @�0�o��}���p�%{�4�T�A��m'��C��%����U;���H��"xr��������Uc5������T:J]iO�gu�����>>k��GA�S?w�����W:,b"
���N���OGo�k�cq�t����:�|���9-�*��2������b}z������d��U��b��\Y^���������1�Y>}�k2�-�4���4����6
zO�Uj��
rw��pce��yI�?PK
L�u@
�PK���P�1 0009-progress-reporting.patchUT
��^-��^%��^ux��Z{s����>���NA`�7�M�b���ul/���w+����Vq|�����gI��$�P.F3=3��u����%kw����5�v���g���:F��i������Y�3����l�Cft�������Q|dNY?vgl�K�g�e��ZD?~^���<��������S$�1���a�:�{�����b�����j��NN��w����>1�O,��y���E<�����b�Z-�8�O��}�}���m�r�D�[��/^0��?3f�Yes�m%t:���/��.�k�_
`u���{.r�b�������c�]�j5]����s3�����&<N`R��	�c8�b�����1���-6s�����s�\o3��y���K���]�p���j�Xt���U�s7a�����>��������J��c��V��8=�m;������fe����������j e�h����f��&�8N�(1�K6�>A>E��hr�8�46
���8���]�k���K��'�k�Z�
��%���V�������L�8��V�"`o�����$-���T>+�b�P8y���k�Tb�,��=pfE���i�K�^q���L������
x��0��%vGR=-4��V@�;l��r*&H����XS��������a�����\���Z��,��n����y�����vg�]�w�������'����������9Ud�x���YRvy�1Y���4F�h�����'�3b9�F����BT���:��f�vA5^��M�Jrc
0A���^'.L\p���7
�d�qT��T~D*?��e[����~��_~�9�/%��Ia
�C?����1���#��xw=�����~��n��9M����at�Z�1��Z�1�����%����v����:���	M����>|d��ed���������H�u��jp$��7�]_��u�����I�2IQ���F���A8��&����_UZ����:[�������E�w��k��y�Ah���TM��HiL����DQ�>S���{�l/B����T�Fw�i6�f�1j5}�����L!��U����loWT�^�$����%�!w��qe'���_A�GG�������kY������;�������r}�D�<�.��<Fq��K�%?DM�� 6�u��b��� p���.��1YpA}����Y�.nUM-w����������e���&��E ������Gg���E����j�'3�^N�fc���e8����c�X��il�����8
���@'���T����80�%�iE'\���ZZTo
����������-&t�K	�M+	��m�rU/`�;��1X����k��I�\�0zye��3!��A������#>��,�"01
{�U�V�5��0���(W�o�A��	���?���P#'$��7W���T:^�%d:��"��`L����$z,/b80���b��]v�b�;_��c}��Qi<|��6���c�@3x�*��{���Bd���kD*��5bb��D���m����^��.�do����9�\o>�gf���g��G�:�B�%9B�~ ��	��g�����~�O�����U��r]�K�qV�I�w�[w�$��.����N'�9�X�R��A�,�}��B�q�,��lL=��V�d�-�u,A8�B>;�a-G�d�P�U�����hd�M �����\XP�Q� �T���/������W�`���������|v����d5&Q����bf���(�Q�n���8��7�~i}�=���'�$�a{mY���4W�f�U���0]��M�,RN;X.��S�|q��C��2�56�I��������z )�K���8��m�U�����m��j����_��H�cr;�_g3��=���������T�y�<�)@�a;_��QN�La2�#����>�a��M*�nS�o�k��U����o�J��e����g�"��+o���E5���%�|7\��R��k�����o[O��(�/:��'������n<��A�[���F.�_1O[9����VK_���r�%����
Tk�����^���������Bw�!L���lb]Z0*J����j��|z2����
F����*�<XZ��7��T�K����B,yAB@�WD�j4Y����6��Yp����mO�Y���EX��@J�[�r�^���t]e�@��#���d����?�����wI���f��%��X�Jy!m����%��K�f6<v01X�_B��P���)�t�B���
��� $= nn�>@�R�R��+�E�%`�P��>;V�;����s�`����c�;:J�R����dF��J�G8�K�r�%���JK`>�Q�U�#��[#p��_�����"*�.���3�O���h-LU��<��������;���� �"���o
2>YK����i�N���jF�����o�",����=X�1����0��d��J�NYc���c�$������#D�� �Z-}$8u�s�u����U�������W[��m>������%)�����O��+���&[jP-�S���2b�3��,�R���(#hm��KCz�����G �Bd2@=N��
�R�����}x���wq���!�>������@'�$F��M���;��V7d�����q���1�"p����T*�1ptW��f2A�A>E���������%���=�VY<.���u��~4?]�:��������}�����:�GH����)�����D��O�Y������PH����t������Ka���t(���
j�Tn}������XH�P�������R�DZ�qJ�������D^i�5����/A�$�Q�S����oK�
��:�q����?��G����S���.^�%J`��*�<R���(�/�����!���F5��i���u���{�Ic`��<p��UA�%��Q�����AU�V�s��H5��p��`��J�XT#�x��B`b�����	\����T����;*�*,7QCa��*�E��(h���������U#�y�
�&������.�p�j������c81/����o&�L��	�H����L���uy0��
����8�&'I�BM8L<��rR4h�+u���FLTMq���Pg�k��D�E>dR��������u��E��1}�z3��+CY�%���S�?<�@�qx;�Y�,��d6~0$U��:��QG�+Y��T�Q�"���[S�����z�2S`e�#�?os8�/� �`��4�.n/���.&������w��h��o��p��{2(K�3�����]�dUhSU&qT.���9��G��_\
W'�
���/���c�5���Q,�4�c�H��!�rA�,��.�i��q�{<A'����z�n���S�"{�����Kw_)�������*�mm�@����0��*9(��a�6|�^7�N�2�J;��@����s� _^|��X0_yi��y����(���s��Ew���NSk��Uc�=�U����X���X~=�$�u���Ne�6�k��@s����/.,�^y
�m�*�jIPVaz(���	�3�Td��l�l*�2�f���|_-�BC�/�V��*t���=w��8x:BG3�"����!�����e���Z9Tk��������z���r�U}.d������K�OR�Q�U��X@
].p������E�o�yGb���0u������|�/<�-'7w�^g:��u��|��c�:
>��>�FO�����~#
cU�����L	k8�$wP]�����X�*LD&�R��7wI���(�~�q���K����S7��Y���:�z�V�-��m�;�C7�:�V�r��3�k��Ka@o6��F>���VJV�L]���s�Ht��+�D�]\���Y��z8������`|����?���18�x<��Ov������Qz]�Q:y�]]��{�+��_W�U�5&�Vfo�0���u[��]j������e7�nS�4zN�V�6t���vo�E�����|�'�M��7z:�!����7�����+.��g�-;��/�ez��k��s���Z	��S��f�����q|z
���z���wz:u���AW���=wW�����&�KRfq�< ��<���A��Y���|6��%�m���gW>{����(��"i(��"j(��"k(��"l(�u�9��6�����3qM�����z�f�R?���w��Qo����PK��s���1PK���P�R 0010-backup-manifest.patchUT
��^-��^%��^ux��<ks�F���_1�Ei>���W�]Z�e^d��8�N
C	+`�����~���(�wU�JY$0��������0�	�i�����A���Mw�i���x"[�fg���i�����x�b(��q ��c�_4����ks,��7W�ff��'��B������:�9��[��X#��h�Dw�&@i�;����\���������������h���?��vns ������j��%����7�w�B9�z�{��"�3j��o�<�����������������(?6!rl��am�DC��x���_[)n�o�)�GB V<������{~��������H��5Z����xS	�����[�����H��[T,�*��/\9���Z��r��DT��^,����9�h�������OZMG��q�S�M����d������l�p�-���k������7+G��@h�I|?����(N�%
{����J�H-�wAx+C�n����Na���^I��=�9�\+.�a�x�	<����=���5&�l��`;f�c-<?n5|���2��������31"w��R���?���3�����!��M6S6���,�������K�2�o�����W�����N��<�w���L�:�0�~<�i�Q�CE�6:��O"�N�Q��I�&�aX��t-���X$2IB�]�c������F�;~��Rh�vl{J������2,�v�"��G�N�8����`5Z�AZ@0��'&A��3&��f����%�F:��bf!����c������@<4�M�9����R<�/����	�h��H�9��YQ3>�+����{��'�(x�-&�{�\<�_+"-�%�S��T&����f��N�2�
�1��1�`f���>�b���4������2�H�[L�b��,������z�!���[w��"�]\E�u�������� �G��II�������8jT@���:������M�"@�f<4���'�q�F��*f^�����<�pjy>��<��o�Z�!��3`m�t@��v��\���un�7�3������i��TH����5b������B����<F!�^�8x����"h��J�p�3a���IZ�x��(l�\����8��]t���������*��m9��JQ�u��|q���I�b9�����mU�������x.���V�TqE���e��S�8=��&Z�@��!Q��2c�I���b{��TKE5|
�p�X����@���e��,��>�07{�S�
*�?��$���d$�p!6?����b��Q�-�����@���C���@)��������d8��$��%>oUW�_����UvW�1n�x����cE�	t�y���i�h��/���i�����a�J(�<��s�I�Y{�����S/�����,�rf
y1X=�jPH�A��B�O2�]
k�i�e�k�]u�=��q���J���q	K{3�b���p��������7Z/������/���
|6
��������:}�;�ep���U�m:`�n`�������F��0'v��0�Yb�S�|�	��nQ$��b{�hn;2�����h���g��yG+j+�H���3K��md�~��5,-�_��C�����W^�m���
8���>�W2�W��b�C����_T�O��!sL����,�irj�'��
�("4�C,�;_G��_�|��&����kY�uvI? }��������\C7�!�nb���e��)���|fz���5Z�T7:m�D�O���YL?�� �pf.�������`[|��I�3>�����}x?
vK�B�_������v/��{��1>/����r
B|d������������������j=�$?f�Q�����b[�TA�?�\���}:���a���O��`>b��/o"��2(�E�r0�_^X�Dg=�����A��/�&��]5��b���)�*�#�"�0��f �$'��
���@��6-�����i���s�O�5�Wh�a�w`<:������XOX�i2k��,���5)/���8H�,�Q�M���g�^�a��e��������8�N3=woR<{�,��)��Bb��������%�?�?�A���z^e%P�3����
��c�X4*����?�Q�"|�a[sl�v
��`�RE�QH��W�����E
�m���i�qq"�$�����s��$D�}L���������AX����Uw��^��I���o�?�`��T2x�Y�7]<P��g�����������R �nk|��r_��Y.`x������bhE_���>0���
��Hc�����	�%�B(�E���GNF�?�*a��~H'`��l��U��������A�7��@y0������j���S��+
gP�pl���.��!�k4D<%aC)o�r���a���5���<N��0V&�,W�(�#i�8���bKj���������!]�1��� ��{����v��Hc2��2Z6#��d��	�� Y4A���o�@��7���M=��[
@�0+���EA9
�B;S��l�w[�����=��x��K%b�$��%�X�f��F�3$27/�O��fx��"7����D0�X(���#!�(��]���KP�")g"7�o%����
���hO���2���D���,�$��	��\''�o��D�'dXH����a���`��u�l@��[(<h��b�N�	�����eV/c1`���@!8`�/	�U���s�� X���������(}0	�	��bf�S�)�d!����*[)��)W�����#ez�^���N
}2�#Q���u������2a�U4�������-��0\<x���il�S]�d�W����U.�o��Y��b��h������*7	�{�6��@W�y��J
���$����3:@z��0X���%
��w&g����R��3K���- ���q�Kd:�f&��sr/�I;tn��RNEh8��;|c�.F=���h�n��`0;�	���qjc�)T�=�<pn)��=`�nK�9%������<kO���s��$��?2��W
C{h�%[�dI=���y������zT5IJ�X3��,���q��Akr$T�[�@�C��&��������U�O.�eH*q���7���Hp�{�[�$&�O*��$��Y9D��0��z�����<Oe�����[��^)�
��`�=�R�>�[Y*�����?�*���$p�<���R���0
������T�<���$R����V���N�)����Z�����/^����D�;g
����N�������C�����;<�QP��B`E8o$����d�{PFp�A�����
��PX�|��$��<8���f����O����ch���5��<�b�e��d����=��u�5���9�TJI�
���j5��>�
�sX|t9
��,��T&K�����%;����2F�
Z.p(Tazk����
�a����Q��$o"� %fs�H����[y�f�$��'�6:��2d�j���!�Lz�r{�������i���L�V���_�4�L�M�V�������Jk
�#�C�-�`~�+�p��BB��9�q���tt��a���2
k4���f��Td�?c�[?����;��C��l���t�J���-x� t�c�!�Xef�F���O���q`�����m@�3xY!lB���������4���X��h-�	��2��H~r��z�'�e��O����!�VW���5���&	E������%���_�k0�S�g�E���Ed?�6[��Q(����C�z��)����CO��Yj����ah��W�3�k��b��D>��F��;��3��B��g_qD�F��H��,�e��vL����r!�[������/����#�<����E�����9`qM��	�1k��P��+��:�:�-����_X�����*�B�\Yn5����kw��/�\I����h����r��
+������f�	��(��&��B�FI��RYT���i�\DRy���f�{���$7b)�[
�����#����g*����_SIk���^Q��Y��:�%�<Vh�.�����}WS���6��Z�:��rd��5RNH�c�H�#B�����8�-8���R1#����Q�JV�$V�I��1�~��H�����7�;�4�y���s��X�����o���,](��� (Y%�]����M�H�T������+���Ln�b�.��'����f�I�D64�(�B������!�E�G� [�KJ���g
�	!����/�f�jR�0��%#���cu����hc�I�`R����B$&�r9[���+��P�2��4�Q������|�*�q�b�(o|��;�$�E�5%�/�����+��U�A�1p�f���]��thZiV��zPX�y>�����G��j�����y�����jM��������	7�����r�
�q@�	�,�B�M)olm���=���N��Yk�U�P�l��r6�fi��\�!���Tg;Y6�?��H�ax(�7�In'.������I;�	�u�6�Q�i�k?p�<���)Ci��|������n��g�%A�u�$M��3&<>��Q��y!�@7���uI�;����MwBo���l���z��^�UVRF^L@�`
���a�_�+�t���W:���t6OW�I��$Q���J���W��	���[�BTNe �R�a��Z8�q��U��%�O��Q�_8(l�/���|-+�f���"U�X����m����|�/�sf�I��>b?�S,�$�S�pB/�T:=�eK_ox  � _a�(<�A��3��|���H�?���]��if��5B��,|��'�%�8R�� �o�
�����?���>{��vq���t�	H ���&h�����ji,�EHI�f����Q�KL7��B��avKH��7K����o���]��p�p�=����Q��<�!Ecx�fd�a�%%3L��,@�cR(�*P{�N@����)�����v�*��`�I�-P=3�t'�����������pf�zojkp�{����-���^*����p���L������w��~k�R7Z����3��N�&'��9<����f7Mx�/��#��u��}��\d�zN=�X~�����,���T�b
G���6����#����xa�ho������.;����.�(0����W5����L�k�p�n�<�~�����j;VU��	V��5��Q%^��P�0R��Bi<�F����%>�w_����O���y�O��uw8�?p0����'v@����W|=���D�;�R-�T��{;��z<]i(�M�55k4����a��~V�Xn�W�K$P�m_��Z���l�T��Q&��8��i�ev�&@�hR��$�bH��;|V!��6XN�7�W~lf����Y^�Y��2�
�H�I�d	_�U���
*X_���p(S��������1~Q�`��cc������(6f97��KK���I�� ���:���Gtf2P)�vB�vS�j����}8nLZ�	
;���N�m���,��{��xE*�V����������Y%��}E����kZ�pV��cs���� f.��v+��f�$����/s���o6N����G���A�m�j�FGNZ��;!����<���G���������oe�����(���~E��}��'��w�����1��=����������t���xl�����Y\C�=������|�6��U�9R���i*{G�en
��y�vf�]�8����+*G����C��h�=��"��"��pd�I\n��y �Hy��[��L��D����7��Q�S A#����#y�������l�c�
S�<H�	��R���88����������+��"R�F$�1������_2�/*Ib��0%Y/�Y�t:��2|8�v_5�� �v4�������m�
��&���=�b��?cv��=,X����2�!8�)��<a��E�G��L�hE�9�M
I#sz������/o�����������_����	��������tY����%��"
������T=3�<�w0/u������yo�;�r%;s�N����J������l&�N�p��I*������s/�3��OE������!������,r������r�.I�y��"��|M��3�t���K�s��;!h�������(�w��%&��
,�J��t�(�'��A��J'�6�4�^t#�`q&���?�Pn������F
�
��1��j��Ii�����$�&�VW�2�������)5�����xO�a�5�E|9��>�n�3i��&��u���@������P&��E�&H�Z��:���G,!%�>��O�v@��e�����j��r�JeQ����P����I&J�x=�l�+A|������Jt�Yg4u�A�B���r�6����@H�&�}����Z�&�4`_��(9��:
��X��&��X���L�yz.yN=V.�&��\�e���_���<��J�#;�mY����q�~�
j9�zR�Y?<�5u)59J��r&�>�$��x
 ��fL+���O��d2]�7de>��%���q ���`�b�Yk�k
Q�������������PK<��ZB�RPK���P����	? ��0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
��^-��^%��^ux�PK���PN�$L��@? ��Q	0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
��^-��^%��^ux�PK���P���;1��7 ��i0003-Parallel-Backup-Backend-Replication-commands.patchUT
��^-��^%��^ux�PK���P��	��'�( ��)M0004-Parallel-Backup-pg_basebackup.patchUT
��^-��^%��^ux�PK���P��\��G# ��nu0005-parallel-backup-testcase.patchUT
��^-��^%��^ux�PK���P� G��rK( ����0006-parallel-backup-documentation.patchUT
��^-��^%��^ux�PK���P���'G}? ����0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
��^-��^%��^ux�PK���P
L�u@
�= ����0008-added-windows-platform-support-for-parallel-backup.patchUT
��^-��^%��^ux�PK���P��s���1 ����0009-progress-reporting.patchUT
��^-��^%��^ux�PK���P<��ZB�R ����0010-backup-manifest.patchUT
��^-��^%��^ux�PK

�o�
#83Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#82)
Re: WIP/PoC for parallel backup

On Tue, Apr 14, 2020 at 10:37 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

I forgot to make a check for no-manifest. Fixed. Attached is the updated patch.

+typedef struct
+{
...
+} BackupFile;
+
+typedef struct
+{
...
+} BackupState;

These structures need comments.

+list_wal_files_opt_list:
+                       SCONST SCONST
                                {
-                                 $$ = makeDefElem("manifest_checksums",
-
(Node *)makeString($2), -1);
+                                       $$ = list_make2(
+                                       makeDefElem("start_wal_location",
+                                               (Node *)makeString($2), -1),
+                                       makeDefElem("end_wal_location",
+                                               (Node *)makeString($2), -1));
+
                                }

This seems like an unnecessarily complicated parse representation. The
DefElems seem to be completely unnecessary here.

@@ -998,7 +1110,37 @@ SendBaseBackup(BaseBackupCmd *cmd)
set_ps_display(activitymsg);
}

-       perform_base_backup(&opt);
+       switch (cmd->cmdtag)

So the design here is that SendBaseBackup() is now going to do a bunch
of things that are NOT sending a base backup? With no updates to the
comments of that function and no change to the process title it sets?

-       return (manifest->buffile != NULL);
+       return (manifest && manifest->buffile != NULL);

Heck no. It appears that you didn't even bother reading the function
header comment.

+ * Send a single resultset containing XLogRecPtr record (in text format)
+ * TimelineID and backup label.
  */
 static void
-SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
+SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli,
+                                        StringInfo label, char *backupid)

This just casually breaks wire protocol compatibility, which seems
completely unacceptable.

+       if (strlen(opt->tablespace) > 0)
+               sendTablespace(opt->tablespace, NULL, true, NULL, &files);
+       else
+               sendDir(".", 1, true, NIL, true, NULL, NULL, &files);
+
+       SendFilesHeader(files);

So I guess the idea here is that we buffer the entire list of files in
memory, regardless of size, and then we send it out afterwards. That
doesn't seem like a good idea. The list of files might be very large.
We probably need some code refactoring here rather than just piling
more and more different responsibilities onto sendTablespace() and
sendDir().

+       if (state->parallel_mode)
+               SpinLockAcquire(&state->lock);
+
+       state->throttling_counter += increment;
+
+       if (state->parallel_mode)
+               SpinLockRelease(&state->lock);

I don't like this much. It seems to me that we would do better to use
atomics here all the time, instead of conditional spinlocks.

+static void
+send_file(basebackup_options *opt, char *file, bool missing_ok)
...
+       if (file == NULL)
+               return;

That seems totally inappropriate.

+ sendFile(file, file + basepathlen, &statbuf,
true, InvalidOid, NULL, NULL);

Maybe I'm misunderstanding, but this looks like it's going to write a
tar header, even though we're not writing a tarfile.

+               else
+                       ereport(WARNING,
+                                       (errmsg("skipping special file
or directory \"%s\"", file)));

So, if the user asks for a directory or symlink, what's going to
happen is that they're going to receive an empty file, and get a
warning. That sounds like terrible behavior.

+       /*
+        * Check for checksum failures. If there are failures across multiple
+        * processes it may not report total checksum count, but it will error
+        * out,terminating the backup.
+        */

In other words, the patch breaks the feature. Not that the feature in
question works particularly well as things stand, but this makes it
worse.

I think this patch (0003) is in really bad shape. I'm having second
thoughts about the design, but it's kind of hard to even have a
discussion about the design when the patch is riddled with minor
problems like inadequate comments, failure to update existing
comments, and breaking a bunch of things. I understand that sometimes
things get missed, but this is version 14 of a patch that's been
kicking around since last August.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#84Ahsan Hadi
ahsan.hadi@gmail.com
In reply to: Robert Haas (#83)
Re: WIP/PoC for parallel backup

On Wed, 15 Apr 2020 at 1:49 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 14, 2020 at 10:37 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I forgot to make a check for no-manifest. Fixed. Attached is the updated

patch.

+typedef struct
+{
...
+} BackupFile;
+
+typedef struct
+{
...
+} BackupState;

These structures need comments.

+list_wal_files_opt_list:
+                       SCONST SCONST
{
-                                 $$ = makeDefElem("manifest_checksums",
-
(Node *)makeString($2), -1);
+                                       $$ = list_make2(
+                                       makeDefElem("start_wal_location",
+                                               (Node *)makeString($2),
-1),
+                                       makeDefElem("end_wal_location",
+                                               (Node *)makeString($2),
-1));
+
}

This seems like an unnecessarily complicated parse representation. The
DefElems seem to be completely unnecessary here.

@@ -998,7 +1110,37 @@ SendBaseBackup(BaseBackupCmd *cmd)
set_ps_display(activitymsg);
}

-       perform_base_backup(&opt);
+       switch (cmd->cmdtag)

So the design here is that SendBaseBackup() is now going to do a bunch
of things that are NOT sending a base backup? With no updates to the
comments of that function and no change to the process title it sets?

-       return (manifest->buffile != NULL);
+       return (manifest && manifest->buffile != NULL);

Heck no. It appears that you didn't even bother reading the function
header comment.

+ * Send a single resultset containing XLogRecPtr record (in text format)
+ * TimelineID and backup label.
*/
static void
-SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
+SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli,
+                                        StringInfo label, char *backupid)

This just casually breaks wire protocol compatibility, which seems
completely unacceptable.

+       if (strlen(opt->tablespace) > 0)
+               sendTablespace(opt->tablespace, NULL, true, NULL, &files);
+       else
+               sendDir(".", 1, true, NIL, true, NULL, NULL, &files);
+
+       SendFilesHeader(files);

So I guess the idea here is that we buffer the entire list of files in
memory, regardless of size, and then we send it out afterwards. That
doesn't seem like a good idea. The list of files might be very large.
We probably need some code refactoring here rather than just piling
more and more different responsibilities onto sendTablespace() and
sendDir().

+       if (state->parallel_mode)
+               SpinLockAcquire(&state->lock);
+
+       state->throttling_counter += increment;
+
+       if (state->parallel_mode)
+               SpinLockRelease(&state->lock);

I don't like this much. It seems to me that we would do better to use
atomics here all the time, instead of conditional spinlocks.

+static void
+send_file(basebackup_options *opt, char *file, bool missing_ok)
...
+       if (file == NULL)
+               return;

That seems totally inappropriate.

+ sendFile(file, file + basepathlen, &statbuf,
true, InvalidOid, NULL, NULL);

Maybe I'm misunderstanding, but this looks like it's going to write a
tar header, even though we're not writing a tarfile.

+               else
+                       ereport(WARNING,
+                                       (errmsg("skipping special file
or directory \"%s\"", file)));

So, if the user asks for a directory or symlink, what's going to
happen is that they're going to receive an empty file, and get a
warning. That sounds like terrible behavior.

+       /*
+        * Check for checksum failures. If there are failures across
multiple
+        * processes it may not report total checksum count, but it will
error
+        * out,terminating the backup.
+        */

In other words, the patch breaks the feature. Not that the feature in
question works particularly well as things stand, but this makes it
worse.

I think this patch (0003) is in really bad shape. I'm having second
thoughts about the design, but it's kind of hard to even have a
discussion about the design when the patch is riddled with minor
problems like inadequate comments, failure to update existing
comments, and breaking a bunch of things. I understand that sometimes
things get missed, but this is version 14 of a patch that's been
kicking around since last August.

Fair enough. Some of this is also due to backup related features i.e backup
manifest, progress reporting that got committed to master towards the tail
end of PG-13. Rushing to get parallel backup feature compatible with these
features also caused some of the oversights.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--

Highgo Software (Canada/China/Pakistan)
URL : http://www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
EMAIL: mailto: ahsan.hadi@highgo.ca

#85Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Ahsan Hadi (#84)
Re: WIP/PoC for parallel backup

Hi Asif,

In below scenarios backup verification failed for tablespace, when backup
taken with parallel option.
without parallel for the same scenario pg_verifybackup is passed without
any error.

[edb@localhost bin]$ mkdir /tmp/test_bkp/tblsp1
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create tablespace tblsp1
location '/tmp/test_bkp/tblsp1';"
CREATE TABLESPACE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "create table test (a text)
tablespace tblsp1;"
CREATE TABLE
[edb@localhost bin]$ ./psql postgres -p 5432 -c "insert into test values
('parallel_backup with -T tablespace option');"
INSERT 0 1
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/test_bkp/bkp -T
/tmp/test_bkp/tblsp1=/tmp/test_bkp/tblsp2 -j 4
[edb@localhost bin]$ ./pg_verifybackup /tmp/test_bkp/bkp
pg_verifybackup: error: "pg_tblspc/16384/PG_13_202004074/13530/16390" is
present on disk but not in the manifest
pg_verifybackup: error: "pg_tblspc/16384/PG_13_202004074/13530/16388" is
present on disk but not in the manifest
pg_verifybackup: error: "pg_tblspc/16384/PG_13_202004074/13530/16385" is
present on disk but not in the manifest
pg_verifybackup: error: "/PG_13_202004074/13530/16388" is present in the
manifest but not on disk
pg_verifybackup: error: "/PG_13_202004074/13530/16390" is present in the
manifest but not on disk
pg_verifybackup: error: "/PG_13_202004074/13530/16385" is present in the
manifest but not on disk

--without parallel backup
[edb@localhost bin]$ ./pg_basebackup -p 5432 -D /tmp/test_bkp/bkp1 -T
/tmp/test_bkp/tblsp1=/tmp/test_bkp/tblsp3 -j 1
[edb@localhost bin]$ ./pg_verifybackup /tmp/test_bkp/bkp1
backup successfully verified

Thanks & Regards,
Rajkumar Raghuwanshi

On Wed, Apr 15, 2020 at 2:19 PM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

Show quoted text

On Wed, 15 Apr 2020 at 1:49 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 14, 2020 at 10:37 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I forgot to make a check for no-manifest. Fixed. Attached is the

updated patch.

+typedef struct
+{
...
+} BackupFile;
+
+typedef struct
+{
...
+} BackupState;

These structures need comments.

+list_wal_files_opt_list:
+                       SCONST SCONST
{
-                                 $$ = makeDefElem("manifest_checksums",
-
(Node *)makeString($2), -1);
+                                       $$ = list_make2(
+                                       makeDefElem("start_wal_location",
+                                               (Node *)makeString($2),
-1),
+                                       makeDefElem("end_wal_location",
+                                               (Node *)makeString($2),
-1));
+
}

This seems like an unnecessarily complicated parse representation. The
DefElems seem to be completely unnecessary here.

@@ -998,7 +1110,37 @@ SendBaseBackup(BaseBackupCmd *cmd)
set_ps_display(activitymsg);
}

-       perform_base_backup(&opt);
+       switch (cmd->cmdtag)

So the design here is that SendBaseBackup() is now going to do a bunch
of things that are NOT sending a base backup? With no updates to the
comments of that function and no change to the process title it sets?

-       return (manifest->buffile != NULL);
+       return (manifest && manifest->buffile != NULL);

Heck no. It appears that you didn't even bother reading the function
header comment.

+ * Send a single resultset containing XLogRecPtr record (in text format)
+ * TimelineID and backup label.
*/
static void
-SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
+SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli,
+                                        StringInfo label, char *backupid)

This just casually breaks wire protocol compatibility, which seems
completely unacceptable.

+       if (strlen(opt->tablespace) > 0)
+               sendTablespace(opt->tablespace, NULL, true, NULL, &files);
+       else
+               sendDir(".", 1, true, NIL, true, NULL, NULL, &files);
+
+       SendFilesHeader(files);

So I guess the idea here is that we buffer the entire list of files in
memory, regardless of size, and then we send it out afterwards. That
doesn't seem like a good idea. The list of files might be very large.
We probably need some code refactoring here rather than just piling
more and more different responsibilities onto sendTablespace() and
sendDir().

+       if (state->parallel_mode)
+               SpinLockAcquire(&state->lock);
+
+       state->throttling_counter += increment;
+
+       if (state->parallel_mode)
+               SpinLockRelease(&state->lock);

I don't like this much. It seems to me that we would do better to use
atomics here all the time, instead of conditional spinlocks.

+static void
+send_file(basebackup_options *opt, char *file, bool missing_ok)
...
+       if (file == NULL)
+               return;

That seems totally inappropriate.

+ sendFile(file, file + basepathlen, &statbuf,
true, InvalidOid, NULL, NULL);

Maybe I'm misunderstanding, but this looks like it's going to write a
tar header, even though we're not writing a tarfile.

+               else
+                       ereport(WARNING,
+                                       (errmsg("skipping special file
or directory \"%s\"", file)));

So, if the user asks for a directory or symlink, what's going to
happen is that they're going to receive an empty file, and get a
warning. That sounds like terrible behavior.

+       /*
+        * Check for checksum failures. If there are failures across
multiple
+        * processes it may not report total checksum count, but it will
error
+        * out,terminating the backup.
+        */

In other words, the patch breaks the feature. Not that the feature in
question works particularly well as things stand, but this makes it
worse.

I think this patch (0003) is in really bad shape. I'm having second
thoughts about the design, but it's kind of hard to even have a
discussion about the design when the patch is riddled with minor
problems like inadequate comments, failure to update existing
comments, and breaking a bunch of things. I understand that sometimes
things get missed, but this is version 14 of a patch that's been
kicking around since last August.

Fair enough. Some of this is also due to backup related features i.e
backup manifest, progress reporting that got committed to master towards
the tail end of PG-13. Rushing to get parallel backup feature compatible
with these features also caused some of the oversights.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--

Highgo Software (Canada/China/Pakistan)
URL : http://www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
EMAIL: mailto: ahsan.hadi@highgo.ca

#86Robert Haas
robertmhaas@gmail.com
In reply to: Ahsan Hadi (#84)
Re: WIP/PoC for parallel backup

On Wed, Apr 15, 2020 at 4:49 AM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

Fair enough. Some of this is also due to backup related features i.e backup manifest, progress reporting that got committed to master towards the tail end of PG-13. Rushing to get parallel backup feature compatible with these features also caused some of the oversights.

Sure, but there's also no point in rushing out a feature that's in a
state where it's got no chance of being acceptable, and quite a number
of these problems are not new, either.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#87Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Asif Rehman (#82)
Re: WIP/PoC for parallel backup

On Tue, Apr 14, 2020 at 7:37 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Tue, Apr 14, 2020 at 6:32 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

Getting the following error on Parallel backup when --no-manifest option
is used.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 5 -D
/home/edb/Desktop/backup/ --no-manifest
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_10223"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: write-ahead log end point: 0/2000100
pg_basebackup: error: could not get data for 'BUILD_MANIFEST': ERROR:
could not open file
"base/pgsql_tmp/pgsql_tmp_b4ef5ac0fd150b2a28caf626bbb1bef2.1": No such file
or directory
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

I forgot to make a check for no-manifest. Fixed. Attached is the updated
patch.

Hi Asif

Verified the fix, thanks.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 5 -D
/home/edb/Desktop/backup --no-manifest
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/4000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_27407"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: write-ahead log end point: 0/4000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label pg_commit_ts pg_ident.conf pg_notify pg_snapshots
pg_subtrans PG_VERSION postgresql.auto.conf
base pg_dynshmem pg_logical pg_replslot pg_stat
pg_tblspc pg_wal postgresql.conf
global pg_hba.conf pg_multixact pg_serial pg_stat_tmp
pg_twophase pg_xact
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

Regards
Kashif Zeeshan

Thanks

On Tue, Apr 14, 2020 at 5:33 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Wed, Apr 8, 2020 at 6:53 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Tue, Apr 7, 2020 at 9:44 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16)
and hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable.
The hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand
dynamically, I think it's
sufficient initial size. max_wal_senders is not used, because it
can be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

Hi Asif

I have verified the bug fixes, one bug is fixed and working now as
expected

For the verification of the other bug fixes faced following issues,
please have a look.

1) Following bug fixes mentioned below are generating segmentation
fault.

Please note for reference I have added a description only as steps were
given in previous emails of each bug I tried to verify the fix. Backtrace
is also added with each case which points to one bug for both the cases.

a) The backup failed with errors "error: could not connect to server:
could not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.

[edb@localhost bin]$ ./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_9925"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
….
….
pg_basebackup: backup worker (1014) created
pg_basebackup: backup worker (1015) created
pg_basebackup: backup worker (1016) created
pg_basebackup: backup worker (1017) created
pg_basebackup: error: could not connect to server: could not look up
local user ID 1000: Too many open files
Segmentation fault
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.13219.localhost.localdomain.1586349551
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show
copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 13219]
[New LWP 13222]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f2226f76a49 in __run_exit_handlers (status=1,
listp=0x7f22272f86c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f2226f76a95 in __GI_exit (status=<optimized out>) at
exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x952ca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffe3dabc718) at
pg_basebackup.c:2765
(gdb)

b) When executing two backups at the same time, getting FATAL error due
to max_wal_senders and instead of exit Backup got completed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 1/DA000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_17066"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
Segmentation fault (core dumped)
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.17041.localhost.localdomain.1586353696
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show
copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 17041]
[New LWP 17067]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f051edc1a49 in __run_exit_handlers (status=1,
listp=0x7f051f1436c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f051edc1a95 in __GI_exit (status=<optimized out>) at
exit.c:99
#5 0x0000000000408c54 in create_parallel_workers
(backupinfo=0x1c6dca0) at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffdb76a6d68) at
pg_basebackup.c:2765
(gdb)

2) The following bug is not fixed yet

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-j 8
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/A0000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_16235"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_hba.conf pg_logical pg_notify pg_serial
pg_stat pg_subtrans pg_twophase pg_xact postgresql.conf
pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots
pg_stat_tmp pg_tblspc PG_VERSION postgresql.auto.conf
[edb@localhost bin]$
[edb@localhost bin]$

Thanks
Kashif Zeeshan

On Tue, Apr 7, 2020 at 4:03 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error
is displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then
the backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel
Backup is in progress then the correct error is displayed but then the
backup folder is not cleaned and leaves a corrupt backup. I think one bug
fix will solve all these cases where clean up is not done when parallel
backup is failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D
/home/edb/Desktop/backup/ -j 8
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot
"pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup
patch then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D
/home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <
asifr.rehman@gmail.com> wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP,

not while the backup is

in progress. So if the backup is a large one, early error

detection would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of
this
error, it is not necessary to make parallel backup do so. Indeed,
it
is undesirable. If you want to fix that problem, do it on a
separate
thread in a separate patch. A patch proposing to make parallel
backup
inconsistent in behavior with non-parallel backup will be
rejected, at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be
relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how
to
make that case actually work, rather than just making it fail
quicker.
I don't currently understand the reason for the prohibition so I
can't
express an intelligent opinion on what the right answer is here,
but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only
intended

to make parallel behave the same as non-parallel here. So, I agree
with

you that the behavior of parallel backup should be consistent with
the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with
an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding

the shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands
you
plan to add before going and implement everything. That will make
it
easier to hash out the design without forcing you to keep changing
the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups
will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e.

BackupID=<unique_string> OR

(2) (Preferred Option) Use the WAL start location as the

BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands.

So that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might
be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether
that's
possible now or not, it seems unwise to hard-wire that assumption
into
the wire protocol.

I was thinking that perhaps the client should generate a unique
backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory
structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the
backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way
is
better. Either way, the backup ID should be something long and
hard to
guess, not e.g. the leader processes' PID. I think we should
generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode
the
result to get a string. That way there's almost no risk of two
backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by
choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably
cause a
lot worse problems anyway, but it seems pretty easy to guard
against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any
need for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared
hash table.
There will be one structure per parallel backup. Since a single
parallel backup
can engage more than one wal sender, so I think max_wal_senders
might be a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that
defines the maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new
file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains
the same
as for non-parallel backup with the exception that multiple threads
will now be
updating it. So in parallel backup, this will represent the overall
bytes that
have been transferred. So the workers would sleep if they have
exceeded the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel
backup as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this
structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication
command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a
backend process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

Hi,

rebased and updated to the current master (8128b0c1). v13 is attached.

- Fixes the above reported issues.

- Added progress-reporting support for parallel:
For this, 'backup_streamed' is moved to a shared structure (BackupState)
as
pg_atomic_uint64 variable. The worker processes will keep incrementing
this
variable.

While files are being transferred from server to client. The main
process remains
in an idle state. So after each increment, the worker process will
signal master to
update the stats in pg_stat_progress_basebackup view.

The 'tablespace_streamed' column is not updated and will remain empty.
This is
because multiple workers may be copying files from different tablespaces.

- Added backup manifest:
The backend workers maintain their own manifest file which contains a
list of files
that are being transferred by the work. Once all backup files are
transferred, the
workers will create a temp file as
('pg_tempdir/temp_file_prefix_backupid.workerid')
to write the content of the manifest file from BufFile. The workers
won’t add the
header, nor the WAL information in their manifest. These two will be
added by the
main process while merging all worker manifest files.

The main process will read these individual files and concatenate them
into a single file
which is then sent back to the client.

The manifest file is created when the following command is received:

BUILD_MANIFEST 'backupid'

This is a new replication command. It is sent when pg_basebackup has
copied all the
$PGDATA files including WAL files.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#88Kashif Zeeshan
kashif.zeeshan@enterprisedb.com
In reply to: Asif Rehman (#80)
Re: WIP/PoC for parallel backup

On Tue, Apr 14, 2020 at 5:33 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Wed, Apr 8, 2020 at 6:53 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Tue, Apr 7, 2020 at 9:44 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi,

Thanks, Kashif and Rajkumar. I have fixed the reported issues.

I have added the shared state as previously described. The new grammar
changes
are as follows:

START_BACKUP [LABEL '<label>'] [FAST] [MAX_RATE %d]
- This will generate a unique backupid using pg_strong_random(16)
and hex-encoded
it. which is then returned as the result set.
- It will also create a shared state and add it to the hashtable.
The hash table size is set
to BACKUP_HASH_SIZE=10, but since hashtable can expand
dynamically, I think it's
sufficient initial size. max_wal_senders is not used, because it
can be set to quite a
large values.

JOIN_BACKUP 'backup_id'
- finds 'backup_id' in hashtable and attaches it to server process.

SEND_FILE '(' 'FILE' ')' [NOVERIFY_CHECKSUMS]
- renamed SEND_FILES to SEND_FILE
- removed START_WAL_LOCATION from this because 'startptr' is now
accessible through
shared state.

There is no change in other commands:
STOP_BACKUP [NOWAIT]
LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']

The current patches (v11) have been rebased to the latest master. The
backup manifest is enabled
by default, so I have disabled it for parallel backup mode and have
generated a warning so that
user is aware of it and not expect it in the backup.

Hi Asif

I have verified the bug fixes, one bug is fixed and working now as
expected

For the verification of the other bug fixes faced following issues,
please have a look.

1) Following bug fixes mentioned below are generating segmentation fault.

Please note for reference I have added a description only as steps were
given in previous emails of each bug I tried to verify the fix. Backtrace
is also added with each case which points to one bug for both the cases.

a) The backup failed with errors "error: could not connect to server:
could not look up local user ID 1000: Too many open files" when the
max_wal_senders was set to 2000.

[edb@localhost bin]$ ./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_9925"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
….
….
pg_basebackup: backup worker (1014) created
pg_basebackup: backup worker (1015) created
pg_basebackup: backup worker (1016) created
pg_basebackup: backup worker (1017) created
pg_basebackup: error: could not connect to server: could not look up
local user ID 1000: Too many open files
Segmentation fault
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.13219.localhost.localdomain.1586349551
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 13219]
[New LWP 13222]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 1990 -D
/home/edb/Desktop/backup/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f2226f76a49 in __run_exit_handlers (status=1,
listp=0x7f22272f86c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f2226f76a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x952ca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffe3dabc718) at
pg_basebackup.c:2765
(gdb)

b) When executing two backups at the same time, getting FATAL error due
to max_wal_senders and instead of exit Backup got completed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 1/DA000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_17066"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: error: could not connect to server: FATAL: number of
requested standby connections exceeds max_wal_senders (currently 10)
Segmentation fault (core dumped)
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ gdb pg_basebackup
/tmp/cores/core.pg_basebackup.17041.localhost.localdomain.1586353696
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <
http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/&gt;...
Reading symbols from
/home/edb/Communtiy_Parallel_backup/postgresql/inst/bin/pg_basebackup...done.
[New LWP 17041]
[New LWP 17067]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `./pg_basebackup -v -j 8 -D
/home/edb/Desktop/backup1/'.
Program terminated with signal 11, Segmentation fault.
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
47 if (INVALID_NOT_TERMINATED_TD_P (pd))
(gdb) bt
#0 pthread_join (threadid=0, thread_return=0x0) at pthread_join.c:47
#1 0x000000000040904a in cleanup_workers () at pg_basebackup.c:2978
#2 0x0000000000403806 in disconnect_atexit () at pg_basebackup.c:332
#3 0x00007f051edc1a49 in __run_exit_handlers (status=1,
listp=0x7f051f1436c8 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true)
at exit.c:77
#4 0x00007f051edc1a95 in __GI_exit (status=<optimized out>) at exit.c:99
#5 0x0000000000408c54 in create_parallel_workers (backupinfo=0x1c6dca0)
at pg_basebackup.c:2811
#6 0x000000000040798f in BaseBackup () at pg_basebackup.c:2211
#7 0x0000000000408b4d in main (argc=6, argv=0x7ffdb76a6d68) at
pg_basebackup.c:2765
(gdb)

2) The following bug is not fixed yet

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -j
8
pg_basebackup: warning: backup manifest is disabled in parallel backup
mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/A0000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_16235"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_hba.conf pg_logical pg_notify pg_serial
pg_stat pg_subtrans pg_twophase pg_xact postgresql.conf
pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots
pg_stat_tmp pg_tblspc PG_VERSION postgresql.auto.conf
[edb@localhost bin]$
[edb@localhost bin]$

Thanks
Kashif Zeeshan

On Tue, Apr 7, 2020 at 4:03 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

On Fri, Apr 3, 2020 at 3:01 PM Kashif Zeeshan <
kashif.zeeshan@enterprisedb.com> wrote:

Hi Asif

When a non-existent slot is used with tablespace then correct error is
displayed but then the backup folder is not cleaned and leaves a corrupt
backup.

Steps
=======

edb@localhost bin]$
[edb@localhost bin]$ mkdir /home/edb/tbl1
[edb@localhost bin]$ mkdir /home/edb/tbl_res
[edb@localhost bin]$
postgres=# create tablespace tbl1 location '/home/edb/tbl1';
CREATE TABLESPACE
postgres=#
postgres=# create table t1 (a int) tablespace tbl1;
CREATE TABLE
postgres=# insert into t1 values(100);
INSERT 0 1
postgres=# insert into t1 values(200);
INSERT 0 1
postgres=# insert into t1 values(300);
INSERT 0 1
postgres=#

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -j 2 -D
/home/edb/Desktop/backup/ -T /home/edb/tbl1=/home/edb/tbl_res -S test
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2E000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test" does not exist
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: write-ahead log end point: 0/2E000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child thread exited with error 1
[edb@localhost bin]$

backup folder not cleaned

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
backup_label global pg_dynshmem pg_ident.conf pg_multixact
pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact
postgresql.conf
base pg_commit_ts pg_hba.conf pg_logical pg_notify
pg_serial pg_stat pg_subtrans pg_twophase pg_wal
postgresql.auto.conf
[edb@localhost bin]$

If the same case is executed without the parallel backup patch then
the backup folder is cleaned after the error is displayed.

[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-T /home/edb/tbl1=/home/edb/tbl_res -S test999
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2B000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: error: could not send replication command
"START_REPLICATION": ERROR: replication slot "test999" does not exist
pg_basebackup: write-ahead log end point: 0/2B000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: error: child process exited with exit code 1
*pg_basebackup: removing data directory " /home/edb/Desktop/backup"*
pg_basebackup: changes to tablespace directories will not be undone

Hi Asif

A similar case is when DB Server is shut down while the Parallel Backup
is in progress then the correct error is displayed but then the backup
folder is not cleaned and leaves a corrupt backup. I think one bug fix will
solve all these cases where clean up is not done when parallel backup is
failed.

[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
-j 8
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C1000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_57337"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$

Same case when executed on pg_basebackup without the Parallel backup
patch then proper clean up is done.

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/
pg_basebackup: initiating base backup, waiting for checkpoint to
complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/C5000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_5590"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
[edb@localhost bin]$

Thanks

On Fri, Apr 3, 2020 at 1:46 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 8:45 PM Robert Haas <robertmhaas@gmail.com>
wrote:

On Thu, Apr 2, 2020 at 11:17 AM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Why would you need to do that? As long as the process where
STOP_BACKUP can do the check, that seems good enough.

Yes, but the user will get the error only after the STOP_BACKUP,

not while the backup is

in progress. So if the backup is a large one, early error

detection would be much beneficial.

This is the current behavior of non-parallel backup as well.

Because non-parallel backup does not feature early detection of this
error, it is not necessary to make parallel backup do so. Indeed, it
is undesirable. If you want to fix that problem, do it on a separate
thread in a separate patch. A patch proposing to make parallel backup
inconsistent in behavior with non-parallel backup will be rejected,
at
least if I have anything to say about it.

TBH, fixing this doesn't seem like an urgent problem to me. The
current situation is not great, but promotions ought to be relatively
infrequent, so I'm not sure it's a huge problem in practice. It is
also worth considering whether the right fix is to figure out how to
make that case actually work, rather than just making it fail
quicker.
I don't currently understand the reason for the prohibition so I
can't
express an intelligent opinion on what the right answer is here, but
it seems like it ought to be investigated before somebody goes and
builds a bunch of infrastructure to make the error more timely.

Non-parallel backup already does the early error checking. I only
intended

to make parallel behave the same as non-parallel here. So, I agree
with

you that the behavior of parallel backup should be consistent with the

non-parallel one. Please see the code snippet below from

basebackup.c:sendDir()

/*

* Check if the postmaster has signaled us to exit, and abort with an

* error in that case. The error handler further up will call

* do_pg_abort_backup() for us. Also check that if the backup was

* started while still in recovery, the server wasn't promoted.

* do_pg_stop_backup() will check that too, but it's better to stop

* the backup early than continue to the end and fail there.

*/

CHECK_FOR_INTERRUPTS();

*if* (RecoveryInProgress() != backup_started_in_recovery)

ereport(ERROR,

(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),

errmsg("the standby was promoted during online backup"),

errhint("This means that the backup being taken is corrupt "

"and should not be used. "

"Try taking another online backup.")));

Okay, then I will add the shared state. And since we are adding

the shared state, we can use

that for throttling, progress-reporting and standby early error

checking.

Please propose a grammar here for all the new replication commands
you
plan to add before going and implement everything. That will make it
easier to hash out the design without forcing you to keep changing
the
code. Your design should include a sketch of how several sets of
coordinating backends taking several concurrent parallel backups will
end up with one shared state per parallel backup.

There are two possible options:

(1) Server may generate a unique ID i.e. BackupID=<unique_string>

OR

(2) (Preferred Option) Use the WAL start location as the BackupID.

This BackupID should be given back as a response to start backup

command. All client workers

must append this ID to all parallel backup replication commands.

So that we can use this identifier

to search for that particular backup. Does that sound good?

Using the WAL start location as the backup ID seems like it might be
problematic -- could a single checkpoint not end up as the start
location for multiple backups started at the same time? Whether
that's
possible now or not, it seems unwise to hard-wire that assumption
into
the wire protocol.

I was thinking that perhaps the client should generate a unique
backup
ID, e.g. leader does:

START_BACKUP unique_backup_id [options]...

And then others do:

JOIN_BACKUP unique_backup_id

My thought is that you will have a number of shared memory structure
equal to max_wal_senders, each one large enough to hold the shared
state for one backup. The shared state will include
char[NAMEDATALEN-or-something] which will be used to hold the backup
ID. START_BACKUP would allocate one and copy the name into it;
JOIN_BACKUP would search for one by name.

If you want to generate the name on the server side, then I suppose
START_BACKUP would return a result set that includes the backup ID,
and clients would have to specify that same backup ID when invoking
JOIN_BACKUP. The rest would stay the same. I am not sure which way is
better. Either way, the backup ID should be something long and hard
to
guess, not e.g. the leader processes' PID. I think we should generate
it using pg_strong_random, say 8 or 16 bytes, and then hex-encode the
result to get a string. That way there's almost no risk of two backup
IDs colliding accidentally, and even if we somehow had a malicious
user trying to screw up somebody else's parallel backup by choosing a
colliding backup ID, it would be pretty hard to have any success. A
user with enough access to do that sort of thing can probably cause a
lot worse problems anyway, but it seems pretty easy to guard against
intentional collisions robustly here, so I think we should.

Okay so If we are to add another replication command ‘JOIN_BACKUP
unique_backup_id’
to make workers find the relevant shared state. There won't be any
need for changing
the grammar for any other command. The START_BACKUP can return the
unique_backup_id
in the result set.

I am thinking of the following struct for shared state:

*typedef* *struct*

{

*char* backupid[NAMEDATALEN];

XLogRecPtr startptr;

slock_t lock;

int64 throttling_counter;

*bool* backup_started_in_recovery;

} BackupSharedState;

The shared state structure entries would be maintained by a shared
hash table.
There will be one structure per parallel backup. Since a single
parallel backup
can engage more than one wal sender, so I think max_wal_senders might
be a little
too much; perhaps max_wal_senders/2 since there will be at least 2
connections
per parallel backup? Alternatively, we can set a new GUC that defines
the maximum
number of for concurrent parallel backups i.e.
‘max_concurent_backups_allowed = 10’
perhaps, or we can make it user-configurable.

The key would be “backupid=hex_encode(pg_random_strong(16))”

Checking for Standby Promotion:
At the START_BACKUP command, we initialize
BackupSharedState.backup_started_in_recovery
and keep checking it whenever send_file () is called to send a new
file.

Throttling:
BackupSharedState.throttling_counter - The throttling logic remains
the same
as for non-parallel backup with the exception that multiple threads
will now be
updating it. So in parallel backup, this will represent the overall
bytes that
have been transferred. So the workers would sleep if they have
exceeded the
limit. Hence, the shared state carries a lock to safely update the
throttling
value atomically.

Progress Reporting:
Although I think we should add progress-reporting for parallel backup
as a
separate patch. The relevant entries for progress-reporting such as
‘backup_total’ and ‘backup_streamed’ would be then added to this
structure
as well.

Grammar:
There is a change in the resultset being returned for START_BACKUP
command;
unique_backup_id is added. Additionally, JOIN_BACKUP replication
command is
added. SEND_FILES has been renamed to SEND_FILE. There are no other
changes
to the grammar.

START_BACKUP [LABEL '<label>'] [FAST]
- returns startptr, tli, backup_label, unique_backup_id
STOP_BACKUP [NOWAIT]
- returns startptr, tli, backup_label
JOIN_BACKUP ‘unique_backup_id’
- attaches a shared state identified by ‘unique_backup_id’ to a
backend process.

LIST_TABLESPACES [PROGRESS]
LIST_FILES [TABLESPACE]
LIST_WAL_FILES [START_WAL_LOCATION 'X/X'] [END_WAL_LOCATION 'X/X']
SEND_FILE '(' FILE ')' [NOVERIFY_CHECKSUMS]

Hi,

rebased and updated to the current master (8128b0c1). v13 is attached.

- Fixes the above reported issues.

Hi Asif

I have verified the bug fixes, out of 3 bugs 2 are now fixed but the
following issue is still not fixed.

*A similar case is when DB Server is shut down while the Parallel Backup is
in progress then the correct error is displayed but then the backup folder
is not cleaned and leaves a corrupt backup. *

[edb@localhost bin]$
[edb@localhost bin]$ ./pg_basebackup -v -D /home/edb/Desktop/backup/ -j 8
pg_basebackup: warning: backup manifest is disabled in parallel backup mode
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/A0000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_16235"
pg_basebackup: backup worker (0) created
pg_basebackup: backup worker (1) created
pg_basebackup: backup worker (2) created
pg_basebackup: backup worker (3) created
pg_basebackup: backup worker (4) created
pg_basebackup: backup worker (5) created
pg_basebackup: backup worker (6) created
pg_basebackup: backup worker (7) created
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
pg_basebackup: removing contents of data directory
"/home/edb/Desktop/backup/"
pg_basebackup: error: could not read COPY data: server closed the
connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
[edb@localhost bin]$
[edb@localhost bin]$
[edb@localhost bin]$

[edb@localhost bin]$
[edb@localhost bin]$ ls /home/edb/Desktop/backup
base pg_hba.conf pg_logical pg_notify pg_serial
pg_stat pg_subtrans pg_twophase pg_xact postgresql.conf
pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots
pg_stat_tmp pg_tblspc PG_VERSION postgresql.auto.conf
[edb@localhost bin]$
[edb@localhost bin]$

Thanks
Kashif zeeshan

- Added progress-reporting support for parallel:
For this, 'backup_streamed' is moved to a shared structure (BackupState) as
pg_atomic_uint64 variable. The worker processes will keep incrementing this
variable.

While files are being transferred from server to client. The main process
remains
in an idle state. So after each increment, the worker process will signal
master to
update the stats in pg_stat_progress_basebackup view.

The 'tablespace_streamed' column is not updated and will remain empty.
This is
because multiple workers may be copying files from different tablespaces.

- Added backup manifest:
The backend workers maintain their own manifest file which contains a list
of files
that are being transferred by the work. Once all backup files are
transferred, the
workers will create a temp file as
('pg_tempdir/temp_file_prefix_backupid.workerid')
to write the content of the manifest file from BufFile. The workers won’t
add the
header, nor the WAL information in their manifest. These two will be added
by the
main process while merging all worker manifest files.

The main process will read these individual files and concatenate them
into a single file
which is then sent back to the client.

The manifest file is created when the following command is received:

BUILD_MANIFEST 'backupid'

This is a new replication command. It is sent when pg_basebackup has
copied all the
$PGDATA files including WAL files.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--
Regards
====================================
Kashif Zeeshan
Lead Quality Assurance Engineer / Manager

EnterpriseDB Corporation
The Enterprise Postgres Company

#89Amit Kapila
amit.kapila16@gmail.com
In reply to: Asif Rehman (#82)
Re: WIP/PoC for parallel backup

On Tue, Apr 14, 2020 at 8:07 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

I forgot to make a check for no-manifest. Fixed. Attached is the updated
patch.

Have we done any performance testing with this patch to see the benefits?
If so, can you point me to the results? If not, then can we perform some
tests on large backups to see the benefits of this patch/idea?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#90Asif Rehman
asifr.rehman@gmail.com
In reply to: Amit Kapila (#89)
Re: WIP/PoC for parallel backup

Hi,

I did some tests a while back, and here are the results. The tests were
done to simulate
a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers | 16
workers
Backup Duration(Min): 69.25 | 20.44 | 19.86 | 20.15
(pgbench running with 50 parallel client simulating SELECT load)

Backup Duration(Min): 154.75 | 49.28 | 45.27 | 20.35
(pgbench running with 100 parallel client simulating SELECT load)

On Tue, Apr 21, 2020 at 9:27 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Apr 14, 2020 at 8:07 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I forgot to make a check for no-manifest. Fixed. Attached is the updated
patch.

Have we done any performance testing with this patch to see the benefits?
If so, can you point me to the results? If not, then can we perform some
tests on large backups to see the benefits of this patch/idea?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#91Jeevan Ladhe
jeevan.ladhe@enterprisedb.com
In reply to: Asif Rehman (#90)
Re: WIP/PoC for parallel backup

Hi Asif,

On Tue, Apr 21, 2020 at 1:00 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Hi,

I did some tests a while back, and here are the results. The tests were
done to simulate
a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers |
16 workers
Backup Duration(Min): 69.25 | 20.44 | 19.86 |
20.15
(pgbench running with 50 parallel client simulating SELECT load)

Well that looks a bit strange. All 4, 8 and 16 workers backup configurations
seem to have taken the same time. Is it because the machine CPUs are
only 4? In that case did you try to run with 2-workers and compare that
with 4-workers time?

Also, just to clarify and be sure - was there anything else running on any
of
these 3 machines while the backup was in progress.

Regards,
Jeevan Ladhe

Show quoted text

Backup Duration(Min): 154.75 | 49.28 | 45.27 | 20.35
(pgbench running with 100 parallel client simulating SELECT load)

On Tue, Apr 21, 2020 at 9:27 AM Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Tue, Apr 14, 2020 at 8:07 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I forgot to make a check for no-manifest. Fixed. Attached is the updated
patch.

Have we done any performance testing with this patch to see the benefits?
If so, can you point me to the results? If not, then can we perform some
tests on large backups to see the benefits of this patch/idea?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#92Asif Rehman
asifr.rehman@gmail.com
In reply to: Jeevan Ladhe (#91)
Re: WIP/PoC for parallel backup

On Tue, 21 Apr 2020 at 2:36 PM, Jeevan Ladhe <jeevan.ladhe@enterprisedb.com>
wrote:

Hi Asif,

On Tue, Apr 21, 2020 at 1:00 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi,

I did some tests a while back, and here are the results. The tests were
done to simulate
a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers |
16 workers
Backup Duration(Min): 69.25 | 20.44 | 19.86 |
20.15
(pgbench running with 50 parallel client simulating SELECT load)

Well that looks a bit strange. All 4, 8 and 16 workers backup
configurations
seem to have taken the same time. Is it because the machine CPUs are
only 4? In that case did you try to run with 2-workers and compare that
with 4-workers time?

Also, just to clarify and be sure - was there anything else running on any
of
these 3 machines while the backup was in progress.

The tests were performed only for 4, 8 and 16 at the time and there was
nothing else running on any of the machines.

Regards,
Jeevan Ladhe

Backup Duration(Min): 154.75 | 49.28 | 45.27 | 20.35
(pgbench running with 100 parallel client simulating SELECT load)

On Tue, Apr 21, 2020 at 9:27 AM Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Tue, Apr 14, 2020 at 8:07 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

I forgot to make a check for no-manifest. Fixed. Attached is the
updated patch.

Have we done any performance testing with this patch to see the
benefits? If so, can you point me to the results? If not, then can we
perform some tests on large backups to see the benefits of this patch/idea?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

--

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#93Amit Kapila
amit.kapila16@gmail.com
In reply to: Asif Rehman (#90)
Re: WIP/PoC for parallel backup

On Tue, Apr 21, 2020 at 1:00 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

I did some tests a while back, and here are the results. The tests were done to simulate
a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers | 16 workers
Backup Duration(Min): 69.25 | 20.44 | 19.86 | 20.15
(pgbench running with 50 parallel client simulating SELECT load)

Backup Duration(Min): 154.75 | 49.28 | 45.27 | 20.35
(pgbench running with 100 parallel client simulating SELECT load)

Thanks for sharing the results, these show nice speedup! However, I
think we should try to find what exactly causes this speed up. If you
see the recent discussion on another thread related to this topic,
Andres, pointed out that he doesn't think that we can gain much by
having multiple connections[1]/messages/by-id/20200420201922.55ab7ovg6535suyz@alap3.anarazel.de. It might be due to some internal
limitations (like small buffers) [2]/messages/by-id/20200421064420.z7eattzqbunbutz3@alap3.anarazel.de due to which we are seeing these
speedups. It might help if you can share the perf reports of the
server-side and pg_basebackup side. We don't need pgbench type
workload to see what caused speed up.

[1]: /messages/by-id/20200420201922.55ab7ovg6535suyz@alap3.anarazel.de
[2]: /messages/by-id/20200421064420.z7eattzqbunbutz3@alap3.anarazel.de

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#94Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#93)
Re: WIP/PoC for parallel backup

On Tue, Apr 21, 2020 at 5:18 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Apr 21, 2020 at 1:00 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

I did some tests a while back, and here are the results. The tests were done to simulate
a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers | 16 workers
Backup Duration(Min): 69.25 | 20.44 | 19.86 | 20.15
(pgbench running with 50 parallel client simulating SELECT load)

Backup Duration(Min): 154.75 | 49.28 | 45.27 | 20.35
(pgbench running with 100 parallel client simulating SELECT load)

Thanks for sharing the results, these show nice speedup! However, I
think we should try to find what exactly causes this speed up. If you
see the recent discussion on another thread related to this topic,
Andres, pointed out that he doesn't think that we can gain much by
having multiple connections[1]. It might be due to some internal
limitations (like small buffers) [2] due to which we are seeing these
speedups. It might help if you can share the perf reports of the
server-side and pg_basebackup side.

Just to be clear, we need perf reports both with and without patch-set.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#95Ahsan Hadi
ahsan.hadi@gmail.com
In reply to: Amit Kapila (#94)
Re: WIP/PoC for parallel backup

On Tue, Apr 21, 2020 at 4:50 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Apr 21, 2020 at 5:18 PM Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Tue, Apr 21, 2020 at 1:00 PM Asif Rehman <asifr.rehman@gmail.com>

wrote:

I did some tests a while back, and here are the results. The tests

were done to simulate

a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers

| 16 workers

Backup Duration(Min): 69.25 | 20.44 | 19.86 |

20.15

(pgbench running with 50 parallel client simulating SELECT load)

Backup Duration(Min): 154.75 | 49.28 | 45.27 |

20.35

(pgbench running with 100 parallel client simulating SELECT load)

Thanks for sharing the results, these show nice speedup! However, I
think we should try to find what exactly causes this speed up. If you
see the recent discussion on another thread related to this topic,
Andres, pointed out that he doesn't think that we can gain much by
having multiple connections[1]. It might be due to some internal
limitations (like small buffers) [2] due to which we are seeing these
speedups. It might help if you can share the perf reports of the
server-side and pg_basebackup side.

Just to be clear, we need perf reports both with and without patch-set.

These tests were done a while back, I think it would be good to run the
benchmark again with the latest patches of parallel backup and share the
results and perf reports.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Highgo Software (Canada/China/Pakistan)
URL : http://www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
EMAIL: mailto: ahsan.hadi@highgo.ca

#96Amit Kapila
amit.kapila16@gmail.com
In reply to: Ahsan Hadi (#95)
Re: WIP/PoC for parallel backup

On Tue, Apr 21, 2020 at 5:26 PM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

On Tue, Apr 21, 2020 at 4:50 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Apr 21, 2020 at 5:18 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Apr 21, 2020 at 1:00 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

I did some tests a while back, and here are the results. The tests were done to simulate
a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers | 16 workers
Backup Duration(Min): 69.25 | 20.44 | 19.86 | 20.15
(pgbench running with 50 parallel client simulating SELECT load)

Backup Duration(Min): 154.75 | 49.28 | 45.27 | 20.35
(pgbench running with 100 parallel client simulating SELECT load)

Thanks for sharing the results, these show nice speedup! However, I
think we should try to find what exactly causes this speed up. If you
see the recent discussion on another thread related to this topic,
Andres, pointed out that he doesn't think that we can gain much by
having multiple connections[1]. It might be due to some internal
limitations (like small buffers) [2] due to which we are seeing these
speedups. It might help if you can share the perf reports of the
server-side and pg_basebackup side.

Just to be clear, we need perf reports both with and without patch-set.

These tests were done a while back, I think it would be good to run the benchmark again with the latest patches of parallel backup and share the results and perf reports.

Sounds good. I think we should also try to run the test with 1 worker
as well. The reason it will be good to see the results with 1 worker
is that we can know if the technique to send file by file as is done
in this patch is better or worse than the current HEAD code. So, it
will be good to see the results of an unpatched code, 1 worker, 2
workers, 4 workers, etc.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#97Dipesh Pandit
dipesh.pandit@gmail.com
In reply to: Amit Kapila (#96)
Re: WIP/PoC for parallel backup

Hi Asif,

I am reviewing your recent patch and found the patch is not applicable on latest master.

Could you please resolve the conflicts and update a new patch?

Thanks,
Dipesh
EnterpriseDB: http://www.enterprisedb.com

#98Asif Rehman
asifr.rehman@gmail.com
In reply to: Robert Haas (#83)
1 attachment(s)
Re: WIP/PoC for parallel backup

Hi Dipesh,

The rebased and updated patch is attached. Its rebased to (9f2c4ede).

+typedef struct
+{
...
+} BackupFile;
+
+typedef struct
+{
...
+} BackupState;

These structures need comments.

Done.

+list_wal_files_opt_list:
+                       SCONST SCONST
{
-                                 $$ = makeDefElem("manifest_checksums",
-
(Node *)makeString($2), -1);
+                                       $$ = list_make2(
+                                       makeDefElem("start_wal_location",
+                                               (Node *)makeString($2),
-1),
+                                       makeDefElem("end_wal_location",
+                                               (Node *)makeString($2),
-1));
+
}

This seems like an unnecessarily complicated parse representation. The
DefElems seem to be completely unnecessary here.

The startptr and endptr are now in a shared state. so this command does not
need to have these two options now. So I have removed this rule entirely.

@@ -998,7 +1110,37 @@ SendBaseBackup(BaseBackupCmd *cmd)
set_ps_display(activitymsg);
}

-       perform_base_backup(&opt);
+       switch (cmd->cmdtag)

So the design here is that SendBaseBackup() is now going to do a bunch
of things that are NOT sending a base backup? With no updates to the
comments of that function and no change to the process title it sets?

Okay. I have renamed the function and have updated the comments.

-       return (manifest->buffile != NULL);
+       return (manifest && manifest->buffile != NULL);

Heck no. It appears that you didn't even bother reading the function
header comment.

Okay, I forgot to remove this check. In the backup manifest patch,
manifest_info
object is always available. Anyways I have removed this check for 003 patch
as well.

+ * Send a single resultset containing XLogRecPtr record (in text format)
+ * TimelineID and backup label.
*/
static void
-SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli)
+SendXlogRecPtrResult(XLogRecPtr ptr, TimeLineID tli,
+                                        StringInfo label, char *backupid)

This just casually breaks wire protocol compatibility, which seems
completely unacceptable.

Non-parallal backup returns startptr and tli in the result set. The
START_BACKUP
returns startptr, tli, backup label and backupid. So I had extended this
result set.

I have removed the changes from SendXlogRecPtrResult and have added another
function just for returning the result set for parallel backup.

+       if (strlen(opt->tablespace) > 0)
+               sendTablespace(opt->tablespace, NULL, true, NULL, &files);
+       else
+               sendDir(".", 1, true, NIL, true, NULL, NULL, &files);
+
+       SendFilesHeader(files);

So I guess the idea here is that we buffer the entire list of files in
memory, regardless of size, and then we send it out afterwards. That
doesn't seem like a good idea. The list of files might be very large.
We probably need some code refactoring here rather than just piling
more and more different responsibilities onto sendTablespace() and
sendDir().

I don't foresee memory to be a challenge here. Assuming a database
containing 10240
relation files (that max reach to 10 TB of size), the list will occupy
approximately 102MB
of space in memory. This obviously can be reduced, but it doesn’t seem too
bad either.
One way of doing it is by fetching a smaller set of files and clients can
result in the next
set if the current one is processed; perhaps fetch initially per table
space and request for
next one once the current one is done with.

Currently, basebackup only does compression on the client-side. So, I
suggest we stick with
the existing behavior. On the other thread, you have mentioned that the
backend should send
the tarballs and that the server should decide which files per tarball. I
believe the current
design can accommodate that easily if it's the client deciding the files
per tarball. The current
design can also accommodate server-side compression and encryption with
minimal changes.
Is there a point I’m overlooking here?

+       if (state->parallel_mode)
+               SpinLockAcquire(&state->lock);
+
+       state->throttling_counter += increment;
+
+       if (state->parallel_mode)
+               SpinLockRelease(&state->lock);

I don't like this much. It seems to me that we would do better to use
atomics here all the time, instead of conditional spinlocks.

Okay have added throttling_counter as atomic. however a lock is still
required
for throttling_counter%=throttling_sample.

+static void
+send_file(basebackup_options *opt, char *file, bool missing_ok)
...
+       if (file == NULL)
+               return;

That seems totally inappropriate.

Removed.

+ sendFile(file, file + basepathlen, &statbuf,
true, InvalidOid, NULL, NULL);

Maybe I'm misunderstanding, but this looks like it's going to write a
tar header, even though we're not writing a tarfile.

sendFile() always sends files with tar header included, even if the backup
mode

is plain. pg_basebackup also expects the same. That's the current behavior
of

the system.

Otherwise, we will have to duplicate this function which would be doing the
pretty

much same thing, except the tar header.

+               else
+                       ereport(WARNING,
+                                       (errmsg("skipping special file
or directory \"%s\"", file)));

So, if the user asks for a directory or symlink, what's going to
happen is that they're going to receive an empty file, and get a
warning. That sounds like terrible behavior.

Removed the warning and generated an error if other then a regular file is
requested.

+       /*
+        * Check for checksum failures. If there are failures across
multiple
+        * processes it may not report total checksum count, but it will
error
+        * out,terminating the backup.
+        */

In other words, the patch breaks the feature. Not that the feature in
question works particularly well as things stand, but this makes it
worse.

Added an atomic uint64 total_checksum_failures to shared state to keep
the total count across workers, So it will have the same behavior as
current.

--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

Attachments:

parallel_backup_v15.zipapplication/zip; name=parallel_backup_v15.zipDownload
PK���P'? 0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
uL�^L�^~L�^ux��Y�s�������Nc�I�[��_��i���f:IF��E���&��{�=��g�I,�g��;��].�pv�C,bY��a���m�Ljw�]���#�����lg����a74��~,�����v�b�a�x.\����7��X<��z��$l���vN=���i@G�+�������=6��wu]�I�P�������7�m����2��x��a�������8
�
cp��i`3/�
�$�cb��QK����Il�y
�vL#��	��.���X�K�������:t��)������i��n��A�U+��hq�OeC��i����lN<�������i^����v�q�o���j��I���S]�Y����j��mg~�
���F���<�u!aqj3
�����R�.Ig#�>�KVn������p6k����6���,HP�s/����q��P��6�{!�?�4h�8�Z
���	�Z������j���i�M�b��O"����$��[�n�����qT�9U4Z����D��T�)q8y���0�/D�z����/>>��L�=j�����Y0�����l�3��m�R�#2x#T�c�1����s�h��	���j6R!�����]�
N]���D�f=�!M�^��I2�a�r�A�<:�Qv8B�^0����}��M��i���=��%���S����+�_�|6���dNWV�jx�C9L
��k�g7�;�J�vM��P2;�)�����qQ
�9D!ZN���p��q����E)�q��DY�DJf-��Y(�s:T���)W��v����2�*;aS �1eih�ey2����-��S�]�4����e��#�}�l�7-�Ut���n�H�y7 �W�����nA�������@nk0��8�6�Y)2i�����/
,�/�&>�j�'v�����2p�;
C���7
\�Q��sd	�p��E����7�g�]\�������g�W��n��o�6��jb�M�BB����HD��
\�D����{'�]tc��R��I����D,�g�[rC��U�(��+�mK9*`��H�_�w� 1��Z��P�]"�����}.���'�=-�l%��D��v��b�
�)�K����������|��B����2��b�����
�QWI\w	W������rI�������F3�0f�T\|%3=�T\S�I�zD��N�m��KU�d:�A5��J�NW�����<�x������`���C�/��\��W�\8�Z��O�i�|�R����B����N*��^
�W�v�[@����$��3���WYE�#���#�.���Tz�U26g��}��W����a�9z"Z�#�����*b}]FL\�!b2`����������X ��[!b2`���(]�)��{��-^�B��w�C�aX<0���"S�~�������DK��[�NH�3NH��pN��7/��@T	��ne���j0������).�#>&M
&T�$��u'��2�4�(�f�@#���B�������������������+5%lio���d_(4'jn�qB9T�,�RAE�i"����n�>�S���/�L���L�MnR��zqJ|B���X�^/��;������%Ky}o |p�:��D�Fco2e���
8��8�Ej���c&�������o@�a�x��(�A�<����w��y�%w^4��2�B��.�~+u�����MD�0$��\�m/!��V�26`8u�7_�x��=7�������
p��Y��j�����t��p	���C2KD�B��������u����M�����?�w ,D�*>Io�aU8�-�=�=�
K�����r��z�������5��C8����WEX��Xt
s<��k���]�xy|+EG�F��������z���a"��M���Q��K���8r���Qa��'������M?��p�� ����E#C����
��'"�<uI|���DVX�V�'[t�/UL�)��yQ����_�a�q'#�3��+6���5;��=�]�51�%�/�i����������|�W��/�fWKp�
���[��������+�����%����/���K���-V����g���O������}v���e���n�,����it���O�->���+�D��!~�|v�p�(z�p|�Py�_Y�����3E�j�����q���>VD��ZN�?��W
�,�n.Ng���~�F�w���-�jPD�O�������j��PK}i���'PK���P�@? 0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
uL�^L�^~L�^ux��[mw�8��B�9m 2���4�v�&��N&��t��3=c���^�4������+�� ���l�����<����{f����}b[G�=j�[m{lv�v�����g'��g��v����{l �<a����Z�F�����n��Y_Lg��~1�K=�/�M��t��-�e����
2X���Z��H<���5�7���`>����3��M���-k���O {lZ����	62����Y�-X�3��BaF��b�#�u��:��:Q��fN�L��X|�����b������ua�al�\�%"fzv���t�c^�,Q�����y�8�j������g&�����/�t&*3��a�a<T�g2r:$*�Y��|��S�NU�/3P��r�qX BT����q�9��h PDx~���o�a�w���XS��`�Z�VfQh�X�����F�qhz�9;��������;k>k3�������P�c��Qi�3���Z�m<��,���"Q���2��;��b����`rB6�!���E"$����z��-\!���������V��><���m��g������I�mu����I���l7���hw:h�M�+�M6���X��8j>30���cO���b��c4S��#����`#��3��`��L\9���`�9v�a`�Y����w=x��
{���������~SYeh���
V��0�U�+�F���"���F�Q�>�����_*M�����g.(.��s�P����r�T����J������vBz3�C��Wl�8<�]���c�Y*�l36�}`�SWx�*qx���{��-����7�[,�sbk�FbP���
�3�h`
/��3��jY�;��)�
���iUJ��5�������H�lf~���7�[T��h����
p��'�f��]�"��X�����;&�����M�0�CrQ*r�+To��N�CE�3l�i!iiF��a�#L��{V��Fb��S��y�2N�?�,x����p�y����Y����M�7_u�W�����o��g�W���f�������mo��.��K�������s��!I�.����!�y
�|]��!�
X��XE������M�*�/L[��
�w���^���WWU��
�����x���/���x�*�[�!�}z��q�s����j-6`r�Rf�R<���a��h>N/H�@���^�%���@X�c�!�K�Q��CX��Q{i=s&���*{��5���l����4�=���H��T����J���=��v>|�,����3hg�1��]y��go��u/�.���Z������T�L&�������UR=�������/���j�DH�^���__^�1��R�"�pM*{�?wm80��g#�=����{��w��������T��u������t�2�^�XV~+EWi�ND�+�}���d{ES?'E?������<������mJ�"��@Pb�+Bh��~RR<q�h2��������d^j��D�r�N�e)�`+E�uH	��,E�a��3j-��$
��BIdP1����ZS(7�����U#`�k������>*D���u�`D�1�}t��[�_eO������o*Kf���a�����
2x��4?�8��+���}�����d����e�f�G��T�>q7�5s�����m3@SX��7�����a��h���^�2B�`�,v�B��TN�����U�|c��J�I���@�p��I�����IEg)��IK��@�H�!v�e`b��x�#�$c���wll
���z������6���Q	�e��&
��vRO��L�S���V<�������S���Z*Vj��p���+����U������^����k+�c��F��WWr���I� z{�F�\��`
��d?��-���t��AKF=�&DC.������iZ<Fi�
|�$�
�4u��^c�+����}��o���3��"����3L@�;Hs������p`�@R^�s���7|���"��~w;���y���]T��,)3��B�0�y�C@`�����$6����gX,g�������`��X|��*y�/�����|�Hw�/�RP�5GBnBH��:n@�������6��W��/����R(@����+`"H�l��x3�(�w��9h��������*�U�����������%�C���'+j�]VR�����t��Q0��[m����������=��Z�������z��Q?�����y���G� f+��w�|	���\��\�w�|�^�f;���X��Q�!|�m��q�^{%h{x�����m��*X��d�������d
��������z���k�[�G@z��J��^�����y����x�
�'Kn����o
������|G������w�z'��$��s����H��
�%bW��q{������?�s��9����������C��F��	S����VC�	S�3:Y��v�	S���C����N��1������s�9�0�������S��GwDV���JS8��&|9����a$���PV��0<H�������"��%@�+R�-T>*F�G�B�g���C?��Cvp�UW)v� �"�u���<���z�($�jg�������%5���[TLMP}3X��Kv��&j�E4wc]y�[;0�]G����g����*_C���F����i��G#�n�9m��������c�mVB��C�G��r9/qJ1��!�C^���.��`���g�������8)�%K�L��*��N�I]KI�B�1�����G��w�I{���S*��TT)A����E���-���������9��w��{����Uv����$��,������]�����g#�H	��"������%C]�=#�O!!s��RL����>�}��������;J��R��v�Bf�B{uUUC:!Ur�vK������H +Qd �1���c��W��$E"`�Q��%���G"�?^f���wR\���T�r9�<k*����W��!?"Vu��~8���C���Y]>=���>�>DQ%�Y�x�eg��C�`�4��4RI���[?��n&H*p�/����,	��P�<�z)t��r[Z�;�M�c������v�0
�����aY>�B�O)-��������'�Qn��O	��!�O
��	~�"mo<�CQv����Qc>& Y{j��	U�(��&i��0!O���?\F�Wo���h�����=Qx���J�v|mu�B�������`_��
1
y�D&	�������@��$��-D6K��� =GI�����Vy�_�o /��4���:c@i��4Dqi�������9)�����'�D$����n���6�g��O3������Y$��J`�����w2����F��D��V@����Rn��#J��0��+�����2�TmJ7
pg4S��-���a����Z�^�����`!�P��f��,�,ca�n��)�A�("�����������A�S^�`N�,���O��\�'9#��&f@^��o�^@:�HC�"	D��;��O>=�)��[�tmN��_l�	5����-�j�����Q.efm�V�T���m�r����=5�Xf)���iM+�E&I��0a
��� �eV�%J�[�0��|�2��5���8�@?�]Zgm|c�����������;��SO�	\�3�-^��:�m��9U!�<R���u�b�S5��e$��	2Yrnx��k'-��=�w�dd��iO9���v0���t�&�����y�v�no��a����5(i�]�C;�
�!���f���]�]�	�7�!������-%g�Vznk2�f2f�Og���ux����NQ���(�����K���n��u�����'�|-o�����v�4�%�������X�,����1W)k7��'�R�N�5�[�����2m�����K������8+�A����X�� �t�`_-�CPHW���G�U�	W��R�5V0��sg��'o�R�6$5w��������L��6��j.����^GIR�c�+Ub)*O\�8�����=��*�*���Y��VDY�9oEX�)����	�"=�Vm��*_B�|@\�Ts��x��7��Y�����
9*/���[X��vw�����l�X�S�7
a�>�
�)���
hif��Y)����	{=%%�va�����e�Vx�k#:���.���&���;�G;n��ruS(�<�t���~^fx��H��UVv"�K�����K����tf�"�qU�MM������� ���K���[_�m��OgG������qC�-�}l���'G'����������]&X�	r��	2�Cw��D���r�?�+���� A����pg:x�C�}��0�%�Hi�����0@�2���^G��X�T�	����G�X.mqiyAq`�0���#���Oc�d(�sg����w�j� ��0&��{
�(�^���z�So�J7 ��81�)����PK�����@PK���P.�7 0003-Parallel-Backup-Backend-Replication-commands.patchUT
uL�^L�^~L�^ux��}iwI��g��L�Bf ��m���5-K��^�z�p
(��@1U�e]����%��Zz����N���\##c���7�?�����m����`�w�w��k�������q{����G����.E�@4��?�j4��7��sqzcq�N��B����z@?�:�&��_:���N�>����u �%[�VC4�����[���k4�����0z.~�p�;y'�;����8��;�����R����A���7t"F8����(,{S/c��V�+��~����-&"��!"_DSWd�V�bxF���E��l)����yLGD�'l���lF�al�B,�pW!���f�������X�����^,j��;���_�������������a�����?��o��=�x�[������G�@��c���(X
��f��g7��N�H,a"N��`��X�|�i��b�_���+G��s�A��������f�M�H��o��SwTgQ�p�!���jT����cUi��\��.�.�H��7�p�N9�il9��?t�P\{��XpTw��`�ZV�7r�7����Fw��9?������������N�����U���t5pq�2�B�r�fn�t``Vo���u����{�<��S,L������
�]���
l:��s��������rt[� ZF������{
Z������Nbq�����6J����[����/���7�'�:'?u~�Kq��q�X��`F��!����\����f��Z�Va0�����sv��Y��|�����������E%Q�";d���T��]�_�c������~�����f���4'��h���_���!���PM���^��3qw����0<����V#wg[:�n�[}*���T��Me�
�P��p�,&��
��[�un@8S�l�����3�������7�Zm�E���}���)z�/���G��ns\����^�5j6�`T��vqj����������Z���hVa9�x8���I��A�g���E(?���w5N0�.��(�v/�s/�_;�h2<-\>T.�z|uqv��Z�����<��K�2�oI>G+��"�����@t\C\Y�H��v`��+�J���/����}=�u���5�`L��b9�{���
�������o���x8�Xr�"��s�N��Y���!�:[�AP���p�,	�����Z:�T�K @#��`5v�	��GN��X�` K L��u�d[<?������.T���h��imp���(�(�` �@-����[�VkM��]��k#��X�!�)�������z)��y��m�K:S����
����:@���� 3�6����E���j�)*���U�4M�,�Y����.KQ��*�f��`����^V�/����d��-8��.�>�=�0�- �d(7�e�_#K�zys`��|Io����\��\�����y��P�m���;���w��O��l@U�,](!���W@4`��9�����/�{���Vu��u�ja��3F����="�7�Q��%)�7�������m������pL`S�#�Qd!n�
���x&� A���Y%������B���#V7��'	1�:6�S�$f^���V�-������[���Ea�UD�x!�}z�p�.��q�!�[�-P�&���A�5��a�������?
o�H��=7�g��@�fLD��4����*j��R���T��T���V4�������3�A#��4�:#�P\��]F�IH�d���@�U����eC�����`���;�|�t�����N�p
��Ew������^�\��Oi(��w����W�x5�>��\N����������[��C��)cI��������;�%��0
���s3�7�F~uB����d��
�����@��9P������#����;��������������b5�r�T;4{o/�#`Y$L�����{��
�v�
{�2�@��}���|B��O9�����C_$��a��s���n���e����Z�nG1B8��uF7�>b��������i�G����!s	�`�M��Z���0����J0��������u_�}��xH�qcxC�@"|�e������*��h���b��	Z�'X:��T��v$6��^�b#��������Z �(��N�����|!�F�O�[�iSl���X�m�q@`�BM���
��� e����mM}�SU\z#1���}`������Iy�Q�%AYN�'��fP��}�foE"��z�^
���R�'��yl�a8H�C��f�RJ���l�^&���@~��a]��j���q#~��>;�Q+�M(�$��F�(<��[�I1U���g��
�����<���!���h����a�@�Pb�9q�7=s���G�$���.3F� p�@��WK L�R4����p������j��v����$��rG`k��#���=�|�J�-$����J��G�D�o^)JLI�K=��w�a6�g?��H�x�r��Z�����*'������}EP�	[�������gs��*X�$EZqw�_-����L��A1ra�}�����L�-}�$G�F�0�U��C����(h�$ba��J�������G9�w���
��t�A�f�7f����/�av#��)b�[�@Y��0�����b�vPfP��T2P�p�K�ya�T=�B�4`�"�4�C�J�������y����K|�NQ�q@���y���LJ��G�S <wn`]@���uY�ScH�L!�=<��������9�YM�gT�G�w�l�a�xn�&�$O96dI��qc��Y�n����#5�M����d�0X�-��m�%m�v�T�����������=�+��
���������+[�����B�7!nko���jV��d�|N�x��Fn����'e�D�Hr��@�h��F:��[Q|���XM�{@��Y��0�1z��|r���2�1�T�l���Dq
Y�a������g
�����.��b�z����,���t��Ko��R�r�PT%�����#��79��$9�c)�fhY`���Nx��$�$���w^( x^��$����)�<���|���p�(Y����z��F����*��
�������vc��i���T!�d��'��3PT��K���� E�l��PH-����c��d���^�;��.q��386�� �����o�4*��A�5^-����:�Ud�^����k��>��K(���F>r����rKf�s�E�/\:�����T\#�wF�;�D��?���:�g�7ap�tH���Wc��l���B4���6"���
Z�3s�nPu���*��>;�G�;�&S4CQK��?��;)�?��
e'��`H� ���pH@�a�w�K��`���C�'�H��M*���	�$
��
��b����QnLXf�*_��T`_(�p(��s9*'�s,�1��l?R�Z:H�9d�����e��
�^���
A����D����%qO����B�����������n��XU�->9]���S�e��}<���{|�q�5�����%
�K�d��X�[c��W�����R(m���.�DTq_�|r��J%
lB���eM�3�J�K,?5V�H�?�kq���!������
95�1��&�C���qs�+���v��� r��A��/>\�]����6���@:F	��A�� '������Rqi.�s|�&����(`�2	\����Te���%iL��=�c�v��z��T 3�hD��#Ws/�hFs�\��Q(��cM���*qA�����M�S��Y�lK�RU4��p�h7yb����5��B� ��V�t$
O2���'���js�p?���������v�}�AjG��i{4�R�����������xvM�b(q_2��D��n�8���F{���,�K�����p���b��X��YX���+�I83|��k�
����Rd_JWb��1&��z�l��bG��]]�z�go�o�:��s�����7�%�o�Ay$~��Z�hC)��G3�qV�����{�F���.����<������n�C��_�L�F��Izf�u����a�S����G�Z�J��gF��\,UK20n����,[��!P�kQ����E�dj�h;9pi��A�u�6k�E��l��$15DC	�S/�P��MlZ���&*�x"z`SG2���R�n����aow?��?��&�_�hz���e�
��b��^�:X�3%��U�vmrO2m���3yRg5c!ol�@�+,�Y��k�5�+V���V��0�g�#B�(�FSd8����Dg�$e4��l~���d�Z�W�do[|��"�4������$�Y$��}��-4@�nH��)w7�_L6mcA�~5�5��l
1P�S��cX�x0���rQ�ek��������Z����A����:a�wu|�}�f%���5�����K�>u5��<_O��������k�c*u�������������u#i/o�������Z0����i��K��A���{-�?��UD.�@fCg����[4�oY�a`����,
.-a���/��
����2ZC|7�Y�5�HJ.�h��F�4��K���:���y��h����+�db��hl����f#���>�����j�T�3�c���c�*l_���������������N���w��������v�=+U����=��A;7������>X�.���.ei���P�i:6�i%!P�U�_���t{��������%�hG����hT�G�$����mK�7o�(H����P��Ad�cwB�;f���Hi[�|)�����/�{fS�/�L�"O��T`w�8�jR.I![��E���>�����B���}�]!�\�^z����
o�N�[kyl\PJ��$D�~�U��p��0�+R��B�4NNY�bC��8��M�`���}�yHT�m 
.��n<.����`i�5|-m����F[��(~�I�{S�d>zGgr����0;D�|���x��C���Q���QF�1�2j�y�Q��Q�e'�b��/�c0%Bc�����o���<8�-���CC�)��M�81�%�S�����b0��O�q�3Z���&c��"�(d/Y|�,��/35��vR!�X��9�G�Q�>Y�����"i��O���m�S%����"@9�xK�����MBO/C�*%�\5��^���N��#]�7�������8B�P�9�l����,�hD
�<d=?���6���
�m����RC[(�s�W{�������n5�34R�?'���ZU��l�@������(�l8�C�L��U��2�'|�#�<�A+T���t�d�d ��4ld��5i�N�A��J{�4?����%�.�O_�
�z�"g��-������-JY-�P2A�X��PQ:�.������Gt���y��v{Ow�BG�)��C���\���)��q�[m��g�������G^��97e��z��K)����"T
����kCMCs�����,�+is���
���OR!�
�d�'��ev��lR�\��/��KVL�J������"VU���+ib�\�����Sv�D����WeF��O�[��	�5fc!��h��s��s��v�7��~�j1ao�0�]Cf4y.���[��Q2��7j9q��`���T������j'��5��"�K�M
'[0�n��s�+� T�i��!r��1�v'�S�{y�c4��j� �
c��6�f
���$C�`�m��g4���2L��j}>����PO�������C��t@`p�Ako.��@/(�	�C�������x������~A.���������g?�����/���)��x3��<����| ���X;!M@6T����MG�-��as���7yCR%�(�a%��{��z�g�<~���5Zk�X�8�����s�jy�A�C��
]�fH5�-�
��Gb�{i�|�����RQ|h�������UD�a��z#<2'�TuB�A�X�R3Y�#���1�������e�����)����|�<�	���[$�����,�w���A[N�r��<En6����M���h��&<��LJB����v��V���JS�e��y�J�w�)<��e���q�����7�f�[i�P_t,��HK��;=��b�SX�GV'�6���hW�*���6�����k�M��b��@�E..t�q��������t�2��2����o�*��[W�L�#+Kb&������n #�Q��(�-m0	8�}md;F�
��u�R�����U^H�:�H���?jx��2��A'<�[N�N<��
KJ1A	�Y����'�M��Px1��f�R�GgG���R#==��`���qn'������AS�M�����`���~�yi�)���C��T�h�'6�I#�gF�����O^�#vEP�t�Lj�g��g�bF�h�*����qPZ�$u�<���&i^	�_A� @�%���'�r'������0�{%����l��j6��t��5h�[yP���0��b�d]u�W���rt�"�	�N�[V���������������n��Q��#�@+�����UD�l#1���$i6��CQi�����-��-+�<V.������r'�;��	� �"��c���D� 2�Ze����n���Yj��a�xs�q�I�w��-~���iC<*Ub���C�qy�I�;kL���~|�*����o��z���>]:� ��H���b�UZ�x���.9�0������J���2t�Rar*�g	v��jI�����l!\�{�E�����1�
e�����&L^�$Y~�/	��a��N������^�5�"W���/�/��.�i��]������\"���vuP�`�)��P������;�K���*&�@�Hb ����Fv�X����(��E��N��I��u�&�69y���Q���g�[8}��8�pp���p�����V�`��o�G��:������}����������3���%�D��^p��!�x��[pJT��	���A�������j���U�y{u�[9��Y�hH���t�D^�[C��~v��Z�q����`7;�����:p�=�u�t>���)_"���9�/�c��<���.I����A��\Z�f�<�bbZ�W�>sJI��.���������������O;�~��dg6TIz"��F�*��U�{�K�p�\(h2�It���)���<91(D�������x��t����g,��Ry=��"�>r-��YK����=h����J=�B=|��>��(m�viQ��p��#o����P�c*�kg���)��2wh)������c@u}k�-��@��ANQb�/���p��'��q��S�n{���a��g�(��@�n�*�����\ [ol�����9I���,C�&*��0�DU��(���!�2r��:�S��o�1�
��1HG"���]��f��+q��'�_��H�3Ju�I^0�5�0=js�CT�����~~��}<=Ec�v�]���X'���+�k�
��������1yww�g������4 (m[,G����i��
#�x�M����Y�j�8�		�HF[S�I�����lV���tK'~N�������b�L��%"d�;�%s��~+a��_NL�Y��L�S2��P;���9qk�x	PY�h=�kP
%�������^�j�����{g:%�������p�@����.�k��	��{�S�F7�����s�FuU��xyW}�v�����-n���Go���{!�����d���j��`r�J��`���|X�,�
�4U ��Ov�Dy��L\u�����-I����t��e�7nAn����Y���Q�LFF�����B�t4(sRZ�zm��������l�#�%?����d�q<"8X�|i&b�^�k\\&�J[e�����"�D����F5��]ia��f��G��k���e�$��S �t���4�y��K���Q=I~P�[�d&�t��f�8����[�1�!��}��������������C��[�#)��|A\;��<0�4pET�EC�8���u�7#�B����.K��'W��:��j '����qoR)3Q�;%�D�(��l�_�E�&���������K;�$t&)L��(��n�������B��J��gu�.���?�t<�L��0�D�1O\��I����`-��`RL�v=�1�
��.���N�mI�}�B����^�����h;H�3�SZujl�����M�'������YYMm�z����i:�{��K��0
0�Q%/�u�N92sJ�	4z�%lM����>t.��+l�`W�8�`������������.{�o�6{]/�I�}`A���\��0 �a|������j@�
���������M����k[{�����d�qq��K�t��zk97�����nA����yO%s�������D
��l$�|���M����g�OF*����Pa�
�U�-�	�����!���X�S��3��xV6j���e�3�>#t�d�����r"E�����2����!5|��i����bnjB�{[fB�A(qj���;����9i����'�`�8�'3���%e��)�HGD�K(��i]�(�n/�����,QT��r-��Y���G�D(���d�\2]0����8���/
9��[��e���R�o��.E���r�_�^�|L
��������2�%V�:\�����B����'��2�K'+�������pci�g����8�?{|���5�$�$ZQ����)�:v�_����-���0merW��d2D���>������~@��)�����/Z�7�����\���.S���
��.+9��a���a�J,�MX����{��SNh�z���s�4���7������9@��D�m�Y���d�������Lx%�S$�$)K���0x�:L;q'�rJg��0���9����5�U[���x��HX�_B��\J0d����I��B��%G!����v~;9��{�K�����&�qL�����w-(����6��,X'�h�r���x�/o�=9�2�5_���=E��G��	3��������]J�dQp�6���������xH�]���6����DUST����-��"�#��������d��Z���Jsz)P��+p������)��
�p}��s��Y���t���PH���D�B�u����i6�HD�`�w�\�0mp�N�[�#�������n���"�~MZ[��9�&�p2�=�2�$�U�$�\��h��{�(����}{�u���83L���s��y`�~0R7TD�<�8sr�4)X��2�6�s��!�B�pC��D���,������*,#��*Dw0���"+'��v��5���R}�	��d�+*����W�N�n\�<4�R=�9�eFY�
�N$����WE��o���:>��"s�[����6������������Pd�J�J�nt��r����:J:������_��w6�Ogqc�(��2~�nzW'�IK������x"�����D<gg�m�Dd�9�g\H��W2�����TIa�������J�d�B��Tt��U�P���Q�gW��;C%w��=,���8ayZ*,q���Yx�r>S*{�I`�	��s����@+vBa]3�F���d�Trw&I��;�!�����J���	4Kd����x2/i��$����F>0r�6"E�s����p4p���y��f�.,������0��L0�N.?|�,\�����H���y|�����1�*T����Mk�l6�o���F������a�	���8.�����4��������P.����uh���t�cR<k�~���()�)Jd����FVt4h���&� �L12����*����z��@�[�������/���BXQ�*���L8w"�V^���E&Nvj�tG��
����-,�%�T�
g�|���f�kW�:x�T�r*�g�7_��6�-���bB��b����X�����z��b���6�����-�0��hJJgdK|�{��a��[����&?��������l-����0������W5~�w..;�?���9blE�"�=VL��Xk ��x�|���=%d:��{�-69��������<F��y�����Z�:�,�qt-�0&��1���O�(�kTQ14i�6����%��X��~������K��y(�7���
���.��o��tJ0>r����T�n�MUn/�NU�X�G�)^���r�����Qd\�*�.�-?�����c�Pf7�P|vta�G]���|��?�L����e�����E}+S�YsG4K7�������v4����4v2N��*��[&��>��zn����UA�x����uz��G������'����j��q��d���>v�6���n�w�V�W����a�����)#��i�'���]���}nQ����MJ��D�J5����I�h�$;T3	�=�����Sc��31I&E1�	[�(��3%���7����f0.o�4%���Df���ar���
������S����%�\����[ �1ki��]�����S��J(�)�R��cBg���m�KT��s���*��|w�BL�/5w��O1�+�M���j+Y�R�%��X{������{�����n|S%P!Q^�R�QSZ5���N���<�24�id6�j)l���<~yC��l�!��/��	%A���[g��=�z��d=������0�C��ND5�l�!/8XW�g����.���r�C�+���������������c����:�/���[q����V�]uv�`�#�+1}�Og^.�I�"�c��������a�����
�vG�}`+��v�X��6��X�T6��N1�����Gk��#���9����~���p.����x�h�������8��}w��+� �Q_	�bE���f�'l'_Qj��;��Nu���3Y[/�L��R��h�x.�� �J'�Zy����������	<��o8�c|6r���px���S)��9]?7�L�}e����a���b��+���X�.�������.���������T{'���d%��Ms��A�M�V����{��a=P���������xd�d��T-%Z������������R��x�W�2p%W@#)�wAWU�
W�[^��l5iQY��O�H�z�x.�6���
L�rXm�}� �Sn������E��U|�=0���/���Q>1��O�:�Y|���w�eA�����W��~~��s.�~�e}����]]�_�w{������;���&���u���'#x�������:{��P*]�I�x�a~�b�K�ACXX���Y�/<|���L�T�`&������o:���"��KHG��&bou(�}��	'�u�
=U����M��
%�������jYC~N�3	Z��,tU"2!i��_�S�v��}�!��������0�'&tO./�q���oq�,d��yq���5�J�u��?/
��w`s�e�p+��^k��T�S:S���=A��I~G��.��3�*�2�;��]!uX7x��m���c'�{lk���yl|P%���,SI�b�)��9�>S�
������NOks��}����;�lYD��d�X��t+HA0��d�P�F��A����p�s�X�2.��A�E�d���h����45����N�	1h����@4����9y���pq��q�eKq������-�w+S��QF]�k���w4�w������94RM0��'(M�w7��%��W����QQ�m�0������v#|}l [��y����������-+W�[%`�'_fp��]AJ�K%55���^�k��C��~K1��nk
�����Tr[)i��nk����;dd���lU�J��dj�;��
?��&����'� @���q����Xl��J����{�?O�K�7c=f�q���������������G�=�`�gJ=���u�reCf�-��ZK�Uk��=Zzsf��U�_�&�'����I��!}��������X�~HG�)�/���u�����()	w�V��������Eb+�sJA��8��<d���3�|�g�[�wj�|�:h���;8�k�C��eo��P�dXf�qD�����T;;N����
�h& rN��������w_u>����Q��T#<�����:��(>�������a���Rc��k�M^�MUm��aWF�����G��>���U������3:[�z��l��[n������
�zMay�-e�m��/<��p�%�#���.�� �d����#z��;�Z=�1; ��yK<�6X���Y2��1~��`Et1���*j��hJ��7kT]�6&�YVC��6A�j�X������* ��*UK����n�������|#,��a���>\�dV)��
�hw��:����m;��s������#�]R�����7��u2�w�<�?���ey/'����l�������.��E]�r|z�����]���J���C�������IY��'�4����i\���S�Y�?!�vef�2GS�]{�p&�����^j��Ek�����^�|��:k<W2J/vF!\���o��_T�Fi�����&�1���r�����_3��%�W,S1elt4!W���B�d�����]�%���x�5�k�k��������^�.��r�������7��*
�.t���e��{�\�=w�x�[Y&��.��Y��a6,~b�X�J�0�I+^�1�c���sB{
���a���P�A���!�c���R�R��/	���3���e4�@�c3q�L9����/�i%R� �0���T����r��������s�����F�9t��2�t~;f���!�2p)�'f��Y�8A�Q���O�Vl!��3`���oQZ+�o��d��5�id��H�]C�Qv����d��1a�K�ejC�~nP3x�i��U�����3=�"f��}O��A������P.g�v���[=��(}�c�S��t�
2�	
��|��<@�f�kr��&���;2�7�2[�(f���iv��v[��[�wG���;j;����\�s���6��]uEB|
R��}�|(���~A�D��"!���J��]����}��T�b��6S����RV�\���d�}�^�����.�S�L��gO�{�mH����W9�*� �������;����b��j���|�����^Tk������PK���ZH4.�PK���P��( 0004-Parallel-Backup-pg_basebackup.patchUT
uL�^L�^~L�^ux��}�[�F����_1�_;�`�;)�BR�M��n����eP�%�$�����=����4�h�}���]@���9�����8�Agg}g����V���7��F��1�v.6z�5{�7�jmn��Q(���ho�Vk��':�V�����I0�����w����
.�.�������K�]�!:[��e��i������n�-�[�V�lr�����������Dk}���$N����x���'c��������w�z4����H�|��a������F0�~"�~��� ����f�jr���H@cl��d2Gq*Q,����E�����8��u�F"��}���d8����LM{���M�i��)�!�����s��$
�Az+n���B�^Z��0HR
� ������?����4��8[x��(���D�1��n�Z�ro���;��S��(��S<�����W�2L""`x%�(zq���J��lVE�V/�p����JO�!��m�\�?�M��+/���
��l��Ga���r��m��?��I�^������2��7����U���������{������Vk���]�v��������UX������D�������[�o����6{�I�K�(I/c?����%x���}7N�b���\�4z|7	���A��{����=�ilo�4�7i"��} �4��R�S8�)�{�����
����#o����0��c/�z-���`�M+��$��w�~�
R|��B�����.W��7��tq���q���������9�<��M�Zv�;byg���q,�c��{/~���.6���j�/Q����
x�w���Z5^�i�
	����Q]V�w��I_����}���[^}^]����D�w~
�!2�!�_�����x���t�����	B`�#f������Ao��FY�6���$��i�����aSq
�
"�/��>y���O/���L�:B�3
F�
#�pX~����TVq�H�0�49���
`��a.�a^����d�0;�<��>.��K��~8�4@/��2����:V��s��I�bA�:���e��W�7�p�uO�u���7�������M���������j���?��'�G��������C������i�t����m�������p����@Du ������Hn������R<���!�G0�<�pX��^����-�i�J��h7�Q��X$��a^���,��Fq�/&)�b��&�����fBC��PM
�8(�}�����! ��o^*G�c��`�!�M}7�+�i�uF_��%H(�l�z����q]?�;~+� 
hG���LPbS��7B��S*vD~+��#�'��	S��JJD��oBW@��
�� �
l��H��;��[����@�G�%!�I��G��?�������W��x w��75����L��Q��IYD�	�k�.|�Lzp %G"�ya�I������W�eW�2�L@a�at�s�ieX���	��)j��(����hNr�H��%�
�����[.D�����)_���pg�P��G)~]dK�|�+�(�n��QN���M��8�	�""��d����DJr3&�p��cY�����
�]�3��j�{��O�����.�h($��� ���P:L4SF=Z1`���V��Q�V�"hyw��&�&��d����N�8=��}�������G�G����ux�&@�32fq�dcS�	<T�&�u>�"	v����?��Z��n��,�
X�_�W��l��
��-8(�b��"�"�fN4TrM�8.���`Az%N~�����V_a	��
R�r��2����r8K�v����	H��;�I���Bk����}�z�e�xP\h�5*�fr�w���=���������uz�n��0��l=�|v)�C���y��0�
}��5~Zo���]'�Qw�C�C�f�7 5�v�dM�;��t�P���M����:d��%�'F^��]My���8(�"}�4��w�*�x�
t��%��Z:M�7����>�H��x�|��^�i{��F���j�MH��x�u�j2[�M�@t�/%)?���LL�mk�k=���[I7H��h��v����`��]�%c�����������j��	������@nS�D�b|h���3�����v�C�|�����������S�~��4O�j|����00!FWG7�$�d��h|{p5	��+�M;����|�����V�gzz����h��`rro(9�{���[FZ�m~�}eaG�$�	��c��������B�Ic������(�o��gpA��BC=NsOi���G�)�!s�����Oi�O�J���/.��������K���~~]��OR��}�`�M�����m ���L�1X�����.�X��M�`�O����f��a�����u��f�����'a�p3��\]e���#���E��u7nB���'�T�C}On�� I�������
d��42��r�x�7��O�a@"��� T�]�;�t�~6�y>)��.��������!�%f����if��h����$�Q����x�m��x� y~�rK���</�b5[�)Rh��q;������}�-O��sH&,"�j�7,s]�'(�������9��n��e�����(�wJ����O�I�R2I�$w�5\���Y�:�nM��l�&M��${g?�����7:������F�s�����Z����a�Y��fs	�M�F����h�)��Z�&���0]��xd���L��)��R�U6������� �e<"�j�U7�1����aV��n���>~���:����S���{��I]v����l�?jc����[�XZL��*�_�	�TxZ!�5X<4T$d@�y\D�h��'�I��$K��Ri���Ha�e"?k
�������)MF"
{��x����p��`p�������Y�o��v�������4[	c!��`�����s�����Z�S�=�5���eWz��F�~���i4�#�c/�@��	5To���=�CD��������=�TP��{_��W6N�`{�g����1�y��@�.j5(bU�[��:�f�����^u�+Z/,��>�hT����c��}"���q`y��8g�p�]��W���&�j�y��d�8B!v��	�*_��	�,���@��7��n�<����i�Fr�;��
���g�0M�B�q�4��t`l�d�����j�Wa��a��_",hG���'
!���N����{{�����3)1E��?V^1z)���}%U�l���	8	�W���#7�L���w%
��"���������7�������������P�2n�Sc�d0S�kE"mjD�W����Y
q�h���"u��i~l{O���A0��������Cr�~���o�k�_HV�{��y�y�Y�����i)A\�H����+�o:A7|��M��
��q����S���� ���8|�<Y}���W�����I]��������SD`>y�&�M�A,J"P�nYl4���Y�&H��
2{� h3=D�=Q�3���)�wm!P4�c��$y�|��<��q?���p�+��VVV���� +����@@�En���e�]�c����M�]J�>�8�&TidFt�_a0��5�,y�k����(`B�t~�4?S���,�L�I�#|�S4B���y�B���N�� ����W����u�l�~���
��eP��*�A��$">�.���7_�8 %�%�����Q\�;������1_e��l��tl����?L
����)����8���f�.�����8S��W'����!������D�y���K$�#���G����<�h��V��U��h*�Ue�CC0�w����/�-i�s����w^��:/|]������=�<t7nFqm�G�Q�.A������O�%eo'?R����������V8?P�o3��f�f��^���P�h����z������������J�F�|�6kQ�Ve-�^W����6��P���X=h}�#�F��&��F�v�����"� �_��&@K-!k�����Q�!MVd�2���ADA�Bp6T�Q\
�d����_�a��18F���AA	�����nDx�t~��f�
�������^G@+h����p��7
��;��~�Q�D�	���d��h4Z���C�<�ht�T84����	�{���~4���������l~�����s�8�<&h�7_���o����!�M�A������[���(��e���m��u��C��4��x�����*��/�����/&��t���wZ�����/��n����a������,�^{n�w����&��y�u��~`��l*d�0�)a+�^/���;~]z����;�x��8T�����u	����eI������_���h��[��k��a�����GY��(�C�U�iXC��t�lD#�/�7�
�����C~\��p�H_�rN,q���+!�00���wGQ����j��GH�K�=@36x����w6�y���:��e�:cwN��������)������������m���'���,2�D��iC��8W
��J�C��$��+��j���z MX�mU9�h��)
�����p�����Kty�j*e_�L�\/��{O��Z���=��6���/s��4#&��$����\�k1���H1g,�����h����d!��� �z�y�E��z�����d@z�A�
9e15�|N�wH#����0U1����6�kg~f��/"����Gx
���Q?���z]�i�g�����Wu����w���`��x��+��T��AX��Y0�PkQZb�4�*������o�[��c�����&����QH���0h�'��HL]a�\�=t��E����t������P��N��x\�m���
g�1m�@��������f�
�	4�c��2�5���4�\"8��r�y����\�n�^ |s
���T.���� �Z�n�[6�lX���6��R�)��Cg����H�9�"~����+P��|�����9��r�T�0��3�������S��_@���������ack��?���=K����[ S"Yvfj;�c�l�_��o�A�y[�>�u�k��P8�����?�,���"�Q�IU45��R$��b���M���$DVv@�<� ���XL����m@�H���iNy�Y��L@���]��IN��+�����������xS*���
=d:8o��5�9����`s���Q���������y��':���z{_��%�
�h��}(S(QVno����0��������y^_�/s*����P�5 ���g
�h[hR���=��@�t����u��&�PUj�)����l���l�9h��S��A8A���F
B��?Msh�F��������e��Mg��,i1��7-1�P���!�F���3�t;��F�m��������T�����
�T���d�vs(v�(S�\:��f��
[f!�Qj����~5��0��Jq�~|`A=;��S�?�/�����QXia
�L����������1�r�+�=2N3��8C#�X���z�:dd��:E�9sU���In�#{�,I��y0������5e�4������
���S���X?��I�C}�����JF���c�����~Bus�x���Z�N��^���������\������\��;��T�v�\��#���BM�(�e0�!1���EG�`�;u1��&����
�fhw�X^.�!�yX;f��bCd'&�2���)���J��,9��
�����^�W����G���A��E���3�����~�:�d������X����y����J��,��LV�i6�W����#��$f�q��1=i�c������im��U�e��J�t!��L'������CY�J��u�N<{�<O���(H]e9���%�K'��oO��T�/��X�d2]�;����KRJ��bK��������>��������G��m����?��-����g�3�|������������{2�J'�������v~8<���O����0�7gc?1���S������D��3N��D�}&�������_6�d�����+����|H [/�z>��A���!�e{v�z^����y�=��r����e������w����X8&���^C9}��^�hlv����x��((��Z��{��GvCi�Cq+ ���iM������O>��3?�
=����o��
�s�kK$V6=t0,�D���s�Aq��`�x2��V�45m��e����g�[��-�uA�@N%��)9�������n�3J�!��O����?�At��^/���J�iN����j�8g�
�^}.d~��1V��UGo&�F�p�Y#��%t/�-5�w:����,���c�{���_gM�c#�-��!�����0g�|e!g�f���kN�_���`a��
��������g�Y�h�\������x-�)����!$QL��7]X|���J��%|MY��+��
��QN�v��P����`h��d�����+��C���;����3�4d���#��E�sl��j��a��t�3�X���g����&#EH\Yw�p1�W���B�q]Y�d������U����	�K���c���k�6��Z@��k!��e���n5���Yg��h�6�N�3<�E��Q�v�8�7S!7Tud�(����F��DsM���@�0S����Jft�>�9 D�����UR�b���E������%p��B?D796�e��g��
�ZN�w;���g�fc��*<�������F.�����7���<�,�,K���N�����hsRY�� ?�"wm,��i���O�g)��;���+�s�k����)�0���hH�Dt2��(��g�����#W����a�������<�rZ�4�2QtR���]Jj�����
J���9����*�kE0NNKvl�*���|��9���`mmN�&�Y����2�?�iN��@|�/M�����S���X���1�Gs�Dj�]/3��f�����t�~����DA�77e!NA]���qx�(�Bb����s��<�T�a�g���0���;�����ta��V������2� �u�
�ia��Y&
�'�95���g����9���m��;�V���7�S��3�r��T�AwQ_(�$���H�����$����yJ���O!���RS!��`�'�*���q�M����'o�����v�~|z���K1�0��=}J8������8<==8~}�}���;=������2-��+�r_��x�fQ���=�u�y#T�r�Q8Q��L}mAF��*'d��:�K�B���Q��;.��[�h�4���d2�^�/��P��v�-�w�V����<k�e�-a��t�$����ZO%#��:7�J����wNcHVI��{�.���E��z�����]]�;k�|i&3G������}<r��B�v�P���X�5��"����J�����*B�3'����N]�A�A:#���h��4~V����������]�o�����t���gg�#�Q@';����������_����e8���Y�M��?%2l�q��%]����4�����f��v8a����I�T��uG����������g��wK�h��Y�������&�ll�����p����R|���Z����h�v��S����@p:x��f7�==�=��yw�~��_�������x���d����6Y?�x�w�Hz�+��6�S��Kw���e7����&@#w���a;��uB���
�-bRUzx���.�r�f�=�� �k�h��u���������X����������zrZ�u~�������������Jev��Z�������Y�d���(�u.S\d9�_���-&�7����Jl�f�U3�������p�����Q)��$B�d����"�_~��e��e��.���T�Q�-�n�y6�[�I?�_\�r3�t��XN9
33f���F�M�;lK.���2�Hen����C8x_�K�Va��y�l)�|g}�����I&tO��������4K���$����O���uQX���2����h.rV����j�XL�z\�udHX�H~�������[Z���za���?��1���6��7�X���
	/X+����4%�<��b�<Dr2����f(LgJN��i��M���lmX&*p������~	>IY�h��W��2���XL���u���:���{Vp���_�-Yw(��eO����
����g�%g���4I�J�9
S����	���	�kw?�������������F�J.*k.h���UU�����tY��*��D���~]�_b�6���
�W>G�*�����G������P<������cj�;��dz�G����n}�E����M������@�%�oA������<�H� �a��X� 7/��W��8I��U)���@��������7n�����G���A�&#>bu{��ROB���%����5�����L	
c
|
7���8h{�oo�yf�
���N�f����AO��]��K���	�x���v5���(�
n�G�]2�������*LC�)�\�������[�����6u�,�r��K}{hd\��G1{;��0C5�c��A�
��d�%�VH�k	 ��4�������p��HY���j,��#Dqvy������zj��>e�'P�`����/���(S��1���6?Vn�0����M$�����1������0t3���?�7�]������
���7<tS��1��L��T�F��=�K�4��x�e�4��vU��]�?^J��M�u�n=���6X����wg�l�G���:��������@c:�����ke��MB.����R�G��=��}�jz��q���i�iv�j���?�i74���j[�c�<�-���<�S��;����&�/Gq'6e�}��,�����V�=���k F�3������G�v3��O�Ee�N�a����_-,/Jo�����G���3i`82I��i)9rA�g.�+���l�����"���N#��l�� ����w@#��,P���"sES*De3P�F4&�%.]���7�I��%m��IH����'� ���d�4o�{�-A�Lg""�
si|P4���������&�x�����f�T�}����
�W������")-]8B;��xHx���h�����KS����c��Y�b�����U�l3��B�l�����l�|�9����K�(4_�����1�P�v�����-�fL�N�&L�TK�P�l�#�yby�TE�7�n���8�������(���}���~���\X��0��m�'�U���Bt�a�%���L�Si�Ud�u�}\k�������,����� �����-�����&`����l��U�0*z�W���i]�&�Q�e��o�k���y�p>����������V���-��{h!-�a���4�d�����G���V�HkKIF����i�����8�j4������L���yo���`.�MR$�53]B9���s�j����j
*��i����oL�d��������jy���'�V�"S9�CY���#�E�q&���9�u�M�<���s��}T��E�1�O��Z,yj�����������{@����IA]��X�By��By�<��:�tn9�10�!pj�s9����NS'�)^�t�&�	�1UaG���(8e��D*�����ej�����+�6�r��r��T"Sb-X��=�i�!WW|W�g]�=�����]��`u\���7�,�������E�bF%cwf����J��IpQa� �U��TT+�T�u��<3u��N�Ju3�Y9�.pH���H���Y�h�+�???=��1���f|<i�������O/"���<�J�$�j.�$o`�kf�����dS$����vM������1rG����y�d\.�>g���|���.�N0����s��8��E.���TiM������H���	�t��8�q�5m�����n������6����Faf��
�KT
�p2�<�)�bh��,�;&%�G YYB�&&%����0��Q`�cD�#4��'�-�(+�_V������%�'�&��T9p�G����i,��$��Uv&?��2�����)RFc���tt}�8�.B���v��/�O����a������B)���+y�jeD~��k:�����(���6T���l#R��+�+��9�J��o�T��$��48����q���KI���z��B'�J��R{��t��O�p���c��]�B�'1�{~��]j�3/.�I ����&��3�3�,=w�|�*=��R'�#*�� ��z�{B��1�,���r�������k&1E�����r����������l�-$�����g�a>VdK?�aJg����n	�2T�8�%M��&QtY08s�=�fX�%GK�q�|:���|I���1��Ho����K>G�S�'S���:e� ����� 1�� ���
�	F����Sh��3������� w0
d4m0��Y�������+5eK�d���(�����:�b�%c��=��,1�=P����A��;_=����<X����4�<�,z�(�2����'���������d���./H���;��'�#8��m���,��F�Y���6�-���
6�����=�+�/M����*��	pH`�2\�����\����U�~���9X��=�w�/���>(_ !A���~�1qcn%*����$PDXQ���Vx����R%������'���"[7��n�C9m���<&Ly{�����N4�wuU�Q��U�M>^�I>�X�Tq.�c8Cs�*��S<8M(l�Hy�BS�o���r{�!$7A��q��N�pt(r��P�]Rd!������l*�I���@��F^Rb��UuP�7FKF]V�F��+J��
���(���`�@�� L�jY��a?�ReVt�^�c��'�U	�]�����5
�ag��D�VvPf���)�%���{����A81��0L����i���=*� ��p�E�4:���$�_������)���������Y�>�3\���_� ��M��]P��U�F���j>��9�8��Z2�/��X�8�w��6������
�������m�6_K��k���@m��+��U�9_@m	�3��_�&G�Y"+�V���Z���w�����B�/e��"�>�;���!,����CaV+�9E�]z�O�A�@q��M���vg}cu�����L�"~|�"|��=K�8\��(�)-r=������%��i�0��K��h��8���2�:}�����S�6Q�i�N0��6��S�l`��Yg02��W,�y��*�2�qK�ru�&���-��^�#������y�g���L��t&#�g�M?����FeL��u<���Z��C�d;�d����e�4}gJq	��EC���0->�(�J�_C�������vi����h���9B�$�j�Q�������*��d�,]����D~��1��>�X������e|��J��������a�,*��T]����l�������.����7�CR���Y���g+�Z��]��9����3�Us)�M�I���[
"7vA!9��4\K��e�����OS��OC���+d��]����J�F�d�(IDUD��_�L�p�W�2h��CT����i�U
X����eX,^�-��Sh��H�+�6�rBg�|������� ^�hC��d(\Vx����+IY}�!���S3+�p�[����#���`8t�)�����C/E��X��[��P����c&��I���1���|lT��WE��@J�������6�������F�����$�c�������-�.�<o�T60��.&��%��3�u\�����>U$�A���aKB(��U���Uc�_u05�}�[U��_�;��I�1������������z��w�W��%g�>g�T���I�0�o��'���m%�(K%�k(�����?��Y\�O�������9�r�s���w�KR4���n��sg�gKb��Y�8�+.��Xkt���'�k��
�s�U�<ng
����$�����oU�[v��ZvM[�,�C\D��j�)�����J[���x_�� m�;��j�PK�S��0��PK���P�G# 0005-parallel-backup-testcase.patchUT
uL�^L�^~L�^ux��<�s�H�?�E���6�O���
E���@RNf�]U[j����P�9�/���{��u��vv3@tt�~���y3�������m�n���n�mg�~�m��������q�q��1���L�����z{��
z�~�-��c���������������;�N���_���X�������O����.��v��O�fo�����G�v��>����z;�~�+y�=Oxl���y��,2���Z����N�������N�<W-3�z,���3x�6K?5�gc���r"�-��RD������1;@
��`�^���m&#�;r�nn�����w<f�������o^�W��5�w�5��t:������`G8�f�u�e��{^
�u��_�b��V�m�����^�6�R0G��P7W<�]"����c��N��[�`o�5,���`���#s���n�F��x���Y���i �I$�G`�~t�u��2w{{�H��I��������f������B+�h6rd7p	3�RD���QAH�f�:p`������=��,B��AxoO?J��(�}6�2�����q��`�]�l>������C��
�+$4HQ�
�W���+��1�{1E4s%�&�_���={f���������`��
�1�D��6Gr�q���m���.Lj��8�����v��1o�Sa_��L6�"x=X�<B�Az�	��;��C�3;��sr�1w=��\`�����F���p$�e��	{n����]���@�>�!W�|<{�l�9��������X<u%��t\������KcWA}��"�nh�-4��o4u>#+q��,��m�n���b��c��b��/[�n�����}{r��Z�����z����#��S�Nif���:H	��o�~��9CB��u����@E2�f���2��l��&�O�H@�
"���1�{�x�������Hxw�E
8|f�0)��:�8�a#ast@���cf���G��9��/m����Ru������>H3��G�P�J�)�H�b��2�)��4�<�F`#�X�R�8���HLA5�P.�Y��3�� b��['��7�s��@�q`�^i
��C�8������m��Mt���S'CA���%�����������MX4������Ly�TtkIN�>d�'���&S���j!c��@�5j+u���u�}�������_��Ez� ���J���gAt �,�C<q		����j�6]��W@N{X��O�� Q~*0�:l�����P�@����#��1�N�
�`�C3��M��G�N��&Cnk�C��
��1��Bf��H���B��j����X��@�Js�|Z����������g=�2^�� >��l���fld�#�aRp�!^�Y���c���O$f������0��y�������#�#0sOR��A���x`\.+.B*�9��tvt|tx��/J��gsX)��H^� ���;�>#�JB_����������������7�����CVZ��M��q+������{J��H_���)<�p"�2"�h��������a�~Z���l����T��kW����3z���������$D%P0��x���@��!V�����O���s/P�fa�s�
����~��F�r��Js�$�:�=�BX���
�~r�,�{���"9���%*����]�����exAW�>3w���z�n���W`�}Py%�AJQMKi�f���& ������������G��������� ����"�S�������kH�h��mW�6eN�
��������������h�i����7�I�R=��)j�g���tO�U^�!����n��<K�z �!�!�'Z�3i��s�����zhR!�tPa`!��!8H��p��z�z=���^�������L���������]�SlA8��2[$4k����`$�bV.-G@��Q������G�U��u��z����f��wX�S@B��S��,^!�z���IVS!E����#��![�&b�5��r:d�0��(�z����T}t�������0���|�/��;���epK�U��yZ�3\Hfe"VV���%���SLi�-�
d�HEe�>t�b�S������I}�"�0�����(W3���$F,�U�Y�X�G��E2�yTVMY9X��q��%i�L0\K���Bl���%#�+MV(1��'�V��N�+}cS�[vn�e#��1�T/���BMT�u����#��B^<%<k(�%C�A�8@EAx���r!1����^�E�b)I�w��M%n�UK@0lP�|�H|X�U]&}x'y�b�F���X�J	��D���X� P��	2��|��ot�k���^�D0����f#�� ���W#�����YC�+�!��(����#Uy��17�0��38d�)2)/+�|$o����%�
��R����Pm����Od,tz/</�B'��$�<�73��/d'�A;��~#fSl	��[�!!J��4�S���)Ks��sL,�����	���cYm���^�Q7d6��~�����D8��^����<K>R��h�������lM����*0v����i����~�0������[T�d:��W��`��UA���fa�n����r�,X4+��M���k���� �����3/�A(@��+8�r0��lz#]J
���0�0�+D��+�L���F�+!�$�jK����l�
�i����b�*@��27@k5:cw��#n���M@�<w��D���x���!���]�$+�T1@hEh�������'C�OP�h�l�u���ng��GLOg�'���`���f�����-B��gMN
���_���]�;�\���h���U�7�F��e�����w5*�%�����T�����fJ�E5YjA�6���
��h�oY�U����$p���:�F�z��`|���^�k�e:�F�g@�{'����9{@��`���MY!���l{�.]@cB���5��
����&�P_d�������FE�s�6"J����S��;��N#��Ba�D�>��[���y��g�����UV�*?_5A/a���"��g��>=��8�\�>9�m:�Px��o�X���3S�4�]v;)NiG
;p���3	����q�^�5�,@QB�Cix�+s,��}l��8F������9L|7��G#n	&�t8C���H�<t�v�h�-�3>�e�x/e��+(��{�y5�dkt���Lr�V5����:�f����%���p]������}�~}����qw�t�sM����)]z��������U.Z\��I�^��ZWq}�]n,V������3���m�Y�������V�x�iE1����Q�GT��
CjHZ�O�t�z4f %,}�-y��5:E���U�(���������$���z��B�qcA��o�[���w����fxr���W����
����+R��!�;��I�
yH�~�V���������]6x�(�5	
��LB�������AZ�U �����@3v��>M��_=$��+O]��w�U�U[m���*����1�2�� G��t�����=�40u<�yC'Q(���x/���#0��K�I��WX������Q�[�3����?��E�	N�'p�'�/~w�dP�9)p����l+gUM�v�,��P>��VbN�&
�OF��a6��>�����_�ow���=�kGo��U���8_ �kg���T��c���R&���hT��'|�����&��d��l	����t�a$\>�p���e���\���&�?�
Yb��������q�H�2��Y�0��K���������_KKzi%��33
P��@}Z���t���/|i`���'l�QZ��w���B#�2FL_����<_��7���jN�<��������YA��/rD(�H�]���c,�k+���l�����&�>5�s-*��O>�=��!�O�
�2#�
���/VG�7�jZJ2��FUV�O}x����0L
���}�}<�8%\��d�8�.�^S����_�J�'q�_����w��)���S���O>*�Xfg���&����z��P
+���������4q]`X�>�Y,@#��.�����������#��� �81v��a��>KD��4.��Y)W��8���6P����{���^W�Q�����������U����/��%����%d�O:�����:���"�+��jI������ZrvN�\]����X���:�r�����.W�%s3_G��#��*�8���}�b%�T�hga�������Z�-�;��2E�#s�C5.�S� ����0~SO�a���z��T��������<?a�L��������B6�[}���� B�`��GC�K&���&J�����������6�L�W�Mg�@P�W$i�I�I�E$
��Q%9��B� !������V6�It����F�8@���)P=�������
J��O?[r}gnC% ����x��������rl�/�/�����B���Jtn�����
?�3��_z���R�_��A8���a��Z���;�����Bu��E���������~:~|��]�I�y�e�c�E1r�++;;O����3W�8�B�8���������R�����G��2�:��"��"T"�5�����>�����d�l	�8�I��PV��d�K�*����>
�Q(-Q�l��:Op�UFg$:J{��z�zD
Sj@{�;e}K�����F0��������
��|�#�6��,�&�/�2U{�����^=�eM��m�1����Q���_���4�rL��������q!/��������v����v���!��~������V��oPK�f
�GPK���P�J( 0006-parallel-backup-documentation.patchUT
uL�^L�^~L�^ux��\{s����_���3�'�,+~���g��u�M|m��w:DB�$�%@����~��/�O�s@�(?;���'[x����g*f�q0��`2���l������������poo,����$|��~T	�)��c��;�����V���c#-'�\�b��}/���n&����������g��������(���l������s���y��t6�<��
v7����R��(��^�)��Py,��TI����:������4�6�L����X��W��3`���i���d3�^��vrK���
a�0z�&2�3�LE�e�{[L&Zd�4��z��	�d�z��4�o����=vd�;�Z�5�����v'���m
�����{g�������Xo��f���^����]o^�TR
5�A R#B�'�D����b
�3��c�����;����F���7<�w@������1����.�gD�G�,������������_���}���?�r�����i5���jy �8k�hm������������>����W����ef`�����������5B 9�\���$�W�?�������3\�<���Te���%��JZ����9H�.�����j�������G�����I�M�F3Z�u#2fKaU�ml�2��~�2�2��"�}R���"u�4-�4jk����Q	%��UiV�n��������V�,2.��	ejB/�}�LX��R3��@N$�/@����������q#����PJ�\��2��\dz���P(����$<���fHB����N�E�DnA�|�w��y-����i���z�J��{�i�j���<K�T������E�p��)B���=��`���	�_d�������y:����S�[\73pC&�&1��q3�<1��!7���'z"�D<��b�O`!�$��������E����;��]������xn���Z�b�>����Z�h����G9�9�	�`�&��.�/"S53�LL�'����EB�vgo���C����b�`�2	�\���\��K�������'���N�m���
���8UD���������\U�~��d���`oV�>��n�.H�� ��@��x*����'
2f���@�@[y��0�T���n*@��5��8}"�s�VQ�w���	@�'s�����f��O.�s�cR���W��������/�+���A��.n��W'��"� 7!x0�E��z�"�vv3zx��dp2�
������$�5�o��No�]�f��T4}��ELA��Y
��\����0���x������L���!�'������
�>��!������xQ��y���n�:'_��B\�����NZ��
@F�����\	 ���c�b�d;�����'P��r
�#�q5��L���<"�]�k����j�_/�L[@�r@�`�ZG?[q����E�S��@� �R�KC�aq�&�>;��&&�[�o��������*f��O�?�PU~px~�fx�}���?����V����#�y[#� ���5lWB�6�j.������	�)6st�)��k�����"u�(Pp%�XO�E��s�/-�����0TQ'�+1\&})H���S�T��O��\g&C���)a�'�pZ	*��'D�D��#�dV<TPk<��h�������^Q"��Y�MZ_s�g�+��q�F3�!��VV�$5�4�����2|>{\�����F'm�����#����D&R�����'�mnU��0/L�[]0F�2C& #�S�Ed�Z%f��t��be�����Y0���X�
���<��j��X������X���9�Z.�PjS�z.���m��x�5�"(�iv2$��8�@��'%�����
�_��c /��������A��?�|�
��h/���_�"b#_�����Q��$k�,Hrc0�5�2�������B�e=�h`�j�������We�W"�j�>�[FKL����������b�3���	d
���Gg����b������]\�D��H�y����VV^1���J9���A��[A,?@�?��a�I_[7��{t�c��NE"�d	;N35���5U�pO���A��8V- ]������G��� �~b�1��a��������F�� ���L��	�\��4H�c���J�[`=.)'kI��(��l�D)%.�P��
���U�j���zRb�)�	`����V�u����_"�0�)c��qe�ZA����S0�2��u��Id
��@�L��rq���Z��g�Bq��
Q}�ag�h��m��U�d�j�6a���S�p�s��4Q�n$�a����&9��VRB,BT'
�m@|��0��7�%��� r9����ISh<�vQ��������Bmm��n�6v��at(z �����z���Xrp�!*t"��v���H.�Y�N�����B"ek���0�]���s��fxR�|9w|r�:F*,rH&���8�� ���iQ�����5n3�{��/�\��U�nf=a��m��L������]�'�\U���B�O�yb�K@�Pk��yY��P�u!��g=�|\l�����n�t�@��E��9�2��7�{rkh�k�C
�M����!����`87W����|>o��x9x'9�jc��8u��O�)�'��A��ZE��j���8��.����e����W=��b�g"��*�����8�}k���_�D����eT���D��2�������l.4X��>�������E����b���_��m��^	h/,)�|X�x
?���m�I�S�C�!aS����Y��W�O]��M�m�]"���OX��������$���b�U$:;��j�z*r�����b�%p�,����q�p�T�[M����V���|k��1	]��Ibv��%�G{����������5����R��u�w@HG����3#6mMX21�Ya�
:r;WT��9����6��iFKEx���-��� �$����1w�,@��"�����R*��nb���)��-��)�V��<�J��f�N���M���/i����D���6�F��$�������x��AjiI��o��4�_�R)��_�r���gdQU��&����L��Y#j��|��FW&N}�Q��\z���=������Dj:��t����1�_\�CP�ua�l��IO�S�����������w/���N�r�G�u�P�:{���'T���1O�b�������'�$������;x�:jt�i���R ��
���<�II�����=�����R�h{��K�5W_���<��X�5�F�� ��?_F�o:Rf9-0JY��2Z:����<6�nv�<�Y���)P��y�b��Y�?��/�_n�/�~��7^BT�����53�fY%`Y�]�4�-��{�
���K!�b��ax��a`(nd��k9q-��l����0��4�8�i��Ef�����u���+��,+�--�y�|��g����=/,���A?��b���n���Wy}�����V�hjj�`;��mx������g$���^N���
/���Bm���h����>}��<������ �����e�O������[��y��Z
�z�0�Am���V�e|��bC�&�N��J���H�r�'��J����"��\�UX��"���9dy��0����@z���;�t�>s�d;���wiD���g�/N~�+�o�[��`�������-����e�������
�2���#\�\����+�n���P�4���?�W<x�K�O��U+��M#��]�J�m���f�P~���*��2wV�X7(<�-�,,Z<e�Jx��#m����N��@Gka��s��/r�I���=pX�wP��#�+����O��{�p?|99�x�x������'H�s���0Z���EY�^EMi��+F?�d$��W=3��qY���N�cI��b�w1�t����,u?:�����^�+��[�F] �:%��_#��[J����Xd���m!��~gw���x�{��,���
#KF�W����F��p�g��S����)��,N!�v�Y����A����(i��{���
��_�X�&�-����C�AO�/��uHW��I�D�n��4��l��5Z?uP�����QE��	S��c�X����mU�.��5Z�E��(��,��Cb
t���D����
\�u�2:���}��SX?��<s��=Y�&����ny���~{f���I0]���	&P*$�����=`j���Q~�}SUh�oiw�7B�R#�@7��'��0\�@��`=[ �
;k���:��p����G)6a����5���t�	PKI6�Oi�JPK���P{? 0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
uL�^L�^~L�^ux��Y�S�F�Y�+6tBl,��:%���(����f4g�d��:�>�h������d��:/�������������5�`��t:[~g�����v����o�t���omomw{;�|V1\�)8[����?�v:N����Ap!��{�?�	��a��#������"��p-}���Y$(��g{������fg���]��?������W�?Bgk�q����[�d��H� �)&2� ��,D�2y*a����b���dc����8�N%72Iy"@�"��Z���A�x��0^����H�Px7�t�W���������35p #	�X�#:��	a����dZo6pdk|I=�j�j~�j������l^-�}y���N��{�v{C�a����.����������������hu{]��M�t��Ci&���<��~���(
����p���C_�r�X�F2�
Oz*�3|Xk���y8�OM&yz�6��1�B���p'"H�'C�L��4���Z��0@Kp}|����*�
GS�{����-������d�n��x�E�Gz�q�s���i��Gz�>J�+�
��p/������-�Go>��A9�o����%��d@<�T�!�J����Q�l��i�@�0����'���6��;Q���gZa��&�oYp,Rw6�a����i�*�O<����'xf���������N�P����T@<��<����P��8*��q��O?�A�A�(��I�
��p����c���B������d�@f����{���&�P����a��o�0~�B�^$E�O]?��3��2uQ��0���F
���,�T=�=F���� j��������I���gob�[��*�����I���0����;����������aJ:�^*Y��/A���^���s�k���Y���.�A�I5P
�}<5�H!&9���Mp��C����_���&��I���$Sr���C����w"���7a�1��zS��X��d�������qL��%��L��/2�����Z$�5Q>o�V������Z-)m�<�t5����k=��g���F�%�Q>A��(�
Q������N%�R��1a��x��f��	�M�o;9��]\�tQ��|*9���8z�Y8�QK��h5���� `Y�����g�G�������[����G)z�L1�E��,��GEnbW&$���8%�j#�Q55y!������J��$�j��u�8���wpqV_E�{f�rpU7������=�,'�2��f�6tl����zv�(&)����l&��h16�H�?J�{�5q�>8�B�eai�X�������jiX�8��7�E�l^�gUU4C
�!�I�W=g�ja	Z�1����
����F2ITR_�d���U�@@�'}{`������fq�����RO���+o[��
��
��j��}��H��H��K�L���T��)O��?V�������
;<��U:E��z]�1
�
x�0Z���.e,����8��H G!�|4���0�,��o�U�"����
�b����m�������[Xh���bf+J$��&�BL)Q���G�A{�����1���g�bE"0���lv�o��jZF]���NE����R��K�:ult����fXh=�n��:��L�A��D��d��k;R���B����!��t��
����Jk����M���l
�X�d�"WX����T������l#�o:�G6�4��g���(�c��44����Yd�Y\n[��*�7i�+
.��d�G�k�Hks�F����������T$���b�*�!
}��0Y�B\uxnc.���O&����U�US7U�
�qJ�,�Zxz�������c&9;�ypUu���?|p'X���t��*���<�3@�!Y�*O+0z�p�������X�um��0
 �B[X�b��w����$U`T��k�+�k0��hh�.���*9A�r:qmS�	�}���^�RO>����$�E�3.�j�=Q����x��O�;f$J:����F���9��,��R��U���d�Jy���l�O�`������^�V��D����rJ�c����y������7���=C
�7��0�4YS�JB���1q\&u���&�
i�^W���5L�,A��7��u�< �C�m����[�\�[�����9]�$����-2������e�*��yd*���h�HM���L�S|�����4�ez�'��FAk�B��1���=��!H�����KY�~�`���xl��<�&?���E-|���z��C#:v���6k����HQo���\Svt�����pT�X�L��n���&�"t�m1q����L�e�MGC�N���J����{�R�zK��xM�f��o?�7��h{E��������
�6k{Q�K�N��/�.�����'{=(�8��s���u����+����g+���Sa��Q=���b+tD0���H�uG�1K!�H3���[W��A���Eu��j��aq���X�����W����Y��{�v�R�N)@����P�Gj=�+H[}�2C8��������P(z8g����H������86k
���A�.���U�����Y���]�c�S���]�p���SO��V_PIG+9���U
��������Y>�R����1�7NQl��������|��
��)&hI#��b��I�����=�y
!=���E���D�y����B��m<'�n�qL�M�Y�����Dr���F����bwV���b1)�����aWoZ�L%|�c$��(����@��b��HB���u"s���� #�������/��e{�q�N�eM��W�3����{��������cw;�+z}S�=�+���g���8&������c�pTl�W.���K�!��0Yy�����Lq���Tr�D�3~8���<8�x2(����
��G���W�N.d'F�����{����������m
��\��'���B�`�,���������b8��(?��3��,B��<4_><K	�������x�R������o��<�B���7)�n>C��H9|���+��2p�(��c����n��
���������
%R�o���B���n��k;P?�N���0k9�~�V�PK[��G{PK���P2"= 0008-added-windows-platform-support-for-parallel-backup.patchUT
uL�^L�^~L�^ux��ks�F�3���u/!���n-��.W��g�l�U��4�B"���w����	��P6hfz�5�]��>S/�v�����l�b���eu:��{�~�m���{p�W����^�?h��&]#�K��
w|�d���@	�����/��b�����%����.|b"h��u.���Y����J�k�nF�������#�������l���Y�S+�E�,!\�V~`��������"I�fS�00[���Vs�`!�[����C��
��P�_)&�kg���E���D�;m�V��O��d��������OB9�}7l-�G�����4��k)�eq�	�	��`��[x
gp����{�\�6��.����K����T���������4%���D<FuxgQgGP/��$Y�mC�9w"`���x@B��_���G�f���uUS���w��)��)Ixf/S{�������
����vo��T�]�#�U|1���%��*�R���� ���o�f7�Oc<Q���f�{�p��L���g{�!!�o�r�&
��0�P����]�P`�F7�����d���s�d.2�,@omFNd���6��%*��:����h.�0cs�A(�_D�Q�D���6���W��<TN���������h�|'��*����b4y��M�}w"��.'�zY~������`��l�]�w����/<��w���:�j��bmE�;Z�\����A'�&t���a���N����u��H�?8������W~��6W������a|3|?���w���~?����-~��t�4����������(�5Qoi1���7���0@�I�	�mM��a+���R�0f�(�9
�Q��U��/~������p�IB)7?N�)20�@�W��7`3�`@�j�����|08�C���r1x�����6U��'y�E9���fB!�_����Q�;!����?�8��On&��p:���n �_F�ri��O�_yV���b��F.�JY$4H�b�i�9������0;�>�?	�F�c$,X�,"kx�l�|"��F�������T`�@~�o�4x����o�0[��3:{�����VCzr��{����;���p*�U*�a6p���Y��B��\����I�5<+��G8�QBRc�R<"�,�%wL
at�AR(+�(lGY.�X�`�oQD�T�����j��z�gBD�������(�f�U�����U��
B[�EB�#��P�>�b�:�iZ�L����[��u�-Zdj��@�jN�w�V��g}�z
�`�h�V��L%]g�r���BC�'(F��9�� ��R3�mRC���qD���>�����#w�����^�����f6�������
qp�~�?Sh��LPL(��YB�_}����Z&-��k���ca=�?���G���<��37�dr��	�����D�1u`���R���S���8���y���hA�5Y�'/�W�E�-J�v)3�����ez&�1X�����1����4����R�����Q��6�����0">����*lm�E-�o��,�0���0\�D�-��j��������e�J�R�64��Nil*@TE�)qxL��%\���xq�N{$�%,�����t\��sC��_eo���y�h�q��,2c�,����P5�MN-H/SO�8����ZAQ��*�
#�7�'��m}�`�xq$9�p~�/g6$c|��TtA7=p!r**���+ �6<��i�����\_��=���[q��Se&7�T9��|��'3k��h���zu��l�d��)�q��\-hvK�1�E�*�����
�Y�~�?
�rl
B���>"Rd>`E���������3*�S�?27Vu�j�C(�q0����l�(���+H����r��I�#����O�;,�F��~���y����������Cy��ha�q;
�	��=Z	��L�<B�/	H@e��������J���Q,�`��)���J�,F���"W	�a����^�W������x.�|Y]��V���Ax�����S`NZ*�aZr��r�S���z�aB��`M��B4��r��s=�G�sKe>^�/��[�q�F8�I��gX����:a���zyD
����=F��-��w�{�����{9FPK��,~[�{!�N���Pr\���K4����G�'�+��5N�N�a@�!v�����r�O���#c��vZ��7���#��.�M�����V��f���^�����Jqo���e�G�
���FW�o?8�G�h��^�|�I��R�0)���'X������k|(q�[���i��z,�w���zRYg��8��HH\D���8����:e�Y�-��&�6���=��b&0�3M����nBw�[L9X!�n.V���<d��
H ��Jvm�iS���5��}F����l�����w�uxp���-�_�HN�=k��6eV�b��(rw�`-������E��i��<���T�}o5%$kn�h���k�[�K�$+�����4��l����*��p0��#:���I%�v��������$I��Y[���)���Q����h��B�a���}�1:�.]l�O_��X�L�H���NV����70��{q�x���x�|Z�<m�&���oq�5f`���WJ�"��E�r�I|Qx�1"J��{8�:F��g��)l���u���������<=������p������Z�W���PK|ez�
2"PK���P�. 0009-progress-reporting.patchUT
uL�^L�^~L�^ux��Z{s�H�>�l�.K`	��Zb��[�����VJ%�t�Vq�Y����A��W�\�HH3==��~��%�����i��������[]�u�V�;��v�p��9mX�1
����<f�qB�X�0��; s�z�?eC>_8!��?�	��y������:o�gN�O����&��	h���X���4�e��r��f'�������>2�/,N�Y���%<���g�r�V+�4q�&�{�C��q]r�%N�:��oA4����b�l3M���:�����4����o�z�G�X�i�a���9~�����eK�;��;�j��O3 B9��b�'�����h���E�Zl��c���p�=Y�d~��WO+ZUgM�y<��A�Z.{�t�j���1��a�LS�C�c�Z��g�z������<�t���zx�ze�����gV3��nZLwmO���gv�9If�W\�{�RJ��x�{i��lE�:i������~�g��&g�o�z��J��
����������M�4vN�
`������,�
�iT��*�r�T::���!����������0�a�j� P�gYHc�C��r9��0����#��H���q�Mnl?� q��G�L1�"���R<��f�2{{`�v�$��r5�|?��F������w���+����4W������h<���m�t4�w�SC!�Q��KE�t�&d�=��I�r�Y�����D�H��F��@hxc F����}�������&7x����;�|X���$�x~;�<�!2�!?�� @�ah�m[��������5������`cpS�����T�>��� ���rx[y�^���m���<j�tk�e���1�N���N�-��x�~�����g�;T8�NW?F�FWxt:��4����g&\\As��Yo�;
�Q�4�`�?�/�$�����9����/�`���M(D�����;�@6�k_��������EpT����-��NZ�������pf�  4��A��*R�6$��j���`h)�s/������)�9��&��s\�^���N�F{?���������yH�����nc��)������;h�����t���-���|��C����<�TK%T���K�_�9hPc��W���hJNn��!���k�H���K�%��iQ\+h��=����7�|y`/"�gk��\�A����{G��{WK��#mac�#��������,Z������Jan�l7Z�O^�����VR�2��&���Bf�j��x��"�=��s�C������e�������&**p�.���,8,+!I��B��T�Q�)2�����a���;,����������A����l�)�&�`uImCx:�^�e_#�c��l���j��o]�uJ�=*�7����il,��AF.$H�xh/C��]A
���i0%-��Yr[��Br������3t�IJ�l�&&�
��'����E���
��D��3&����F	s@��"5�NQ�q����qF�9f�B�|�m��0:"I��!/���,'N��\���
;�3_y�Oo���"@�D(�#1�^���=u���\�D�y��=�5�t%_���L>kO�Nz�����������~��Bh9(~e1c�!�x�9qJ#��V�d_���A8)f��"^^�@P8�C�4�@����P~6;�n����'���2U)�!��b��!�`��vW�[L�a��st����0B9�@`O?X&4�5�}����D0�����_�M+RE��jo��B~�����z���O�Or�6oE��z��m��r}�*#b��[7�jQ���bV�����?�.�
���!)�Rx����wAq`��g�M�L��m+���w,�6v]3q�{D�/�3�y_�{���q�<���u�H�w*���hQ��1��]N�Q��FXfa�O�<����/oB�2�[�&��V�%���Z*}1f�"\� ����*(o��jl�^{�`n�
�\�b���!w�����u��m��?o[w��h�����lJ�x�7C&�Q�[���N��Ro��������g���n�`r�2_"��MH�u�(���6��Z]�>z���-�r�Z��D���J�(J]�x���J{<�]��������j��8Z�K�W�xJ�TZ��&�c3������(�U�����.�u��������l��'���F@��p!:�2�-�D1)����*i��EI�q�-��mV;�fC�^e	��-<T���p������#���!��:0��lp�am0����E��9��b�
�DOx+\Z�B�!��(��B&�qA
�_.zxE�H�5)Uv�y���h�����9��I #MS�I���@\[B+RSPr��� s���������9���U��F$0!��b�����*$��!���+�)�����Z0L���>z��c6;
��w�E�����r�%���}�P�A��pn��w������D![��D)+�;��s�bN|�D�
r���*�{U�M���x��L��!Z*��1���|�k���������u�2�(eX<o0�r+~��e�qW���bP�x�+��IM�`P+����b�%2b�W��"����QF��5����/���: �D�(l�z��kUfK���k���
�� =D��!�ct����D's'JB�e�0���i�����C�{�\/�#��OS(�<������dY��%������(�����@��2`���u����)?dj~��������
��r�x �y�X��dL��u*@]��[��y,���)����<��P-�R�!1���0"���$A$�b�e~�B��!���R��( �6�(�N���T��5�t��\P����4+�����4��Y�U�����N��q�t7����J���j;J�j��4,���S�K�H�<���=g�E��(!���"Q��AD�O���a&!a� #��N����Rk�>A�|�7>�Q ��f����(Z���9%t)�dT���WQ0����e����V�J!�) ��3�.kf5O���o�GW��P���@MZ��/��������_�.cy�����#��0�!�[af�#,�T�o����Gg��j�{<�&oC�������h�1�a�SVT�:z]�Q�y��S+M�|��Dg���Q%f��
���pxzy��/���:�/.��������~�c�){�~U2�`�"�U^�QX[������_T���vO
�L}���_�)��)G ����t�����o�O*�j0��3AJ}��B4�O������qR���v�~�5���*������};���i v������nTl�A�Ry���As��������1��H��cG;L������s���_��4H3��F��_P���	E�������h�%wbZ��l?1��x��Bg�1��:?�H����*;���u�N���B��Hx��2P��6��}4�����#�$d�Z������&h�
����y^�P��75l�	�P���c���<��3�+�p��}QB �Wm��3�
���������{B4����Zcd�y/#���=���)y'������fl��C��� ��@�������7w�.��&�e�i�&uu��U�U�yVY&In��^%����"�(�$��;	�~��|����{������?^���FO�����~#�g5Yc��VVu�s�v�Z�q�Z���������Q�=]*���?y����cF��A�iv,�������at,�v�?y�Z�5�C#����m��Fx5
������/6��C���:�W||���$������
#�~OTs�'E���H
��}ftP3NN�8v�V_��L�<]�A�!m{�{�'|�tr��oY���,�=��x�uMym�kS^-ym�k[^���#�]E�P7���H����������������r��,[���2���I�b��kVn�V�d�^�������hW���PK�s���.PK���P�f 0010-backup-manifest.patchUT
uL�^L�^~L�^ux��<�s�6�?K�Kb9�d��j�:�������6�K;��l^$R%�8�\��o	R�i�f>O&�H`,�����h���D��n�5��
{�v�z�i�Nk�m�:���Z��M������������h����Ks$N"o"�������6���������:�9�����#d�FK��C�(��v��s *�N�^,���N|$��O���E���h�!���a1���(.��jQD���o����r>�;��[�t��#�#���������������#�������8�>��Y�Nh8��8�u���eX��NW]<o~=J����&�+m����<��.\����h�V����>��z�}�g_L����sc����D��#<?�!v���]Kt��S������M&�Z��ba�m�����=�����-mw�����j���s8�������v��!�����?�j�n!���+~��(��,J���F{��7�_�����E�O/������x*��u|#�0,nm0����%�>�w"y�9�P,�@��[�.7�G	�t���OZ"
`;�R���_J��97���I���\\�y���#�o �;1����x���2���d�.L@45y=	�d�<�>/&H\8q������(�;0������X=���n=�O�[�.����[�~.V���/���}���=.V�� ^�lO���=�;f�������<�Z�vl�Dq����!t�V�]�x��\��xnQ��^��S��Rw_��J�7�#��������wv1�ws���<�-V����Q8�'���(
@��l��g��������pt��_����������K9�$�cU���K�vJ�@C9��'64���l�!�^���f������N����ORi��S|�*�����v���o�r�"%u;��N�: :�vaNd���Na���g�i��y��4�
Y���V�oe������<1
'�d,��C��Y�^�Q|������U���+�0@���#��~�Ki��KH�y_R�o��,���n��o�`|y�������4���E(�`��$�.h���\LH(_��bR�K��]_%q,a���
�X
/�b�6D�������I
��+$W*��qv8���
?Oc`�;������GP
���
��������	����+�����W�� +"����#G��XF#P=Hyul�����r��d~� ��n��%Q�"�;�C�$p��g'��uLk	cu�<nK���������
wJ�7�CB����r�k%��(`HZ�e�b���7�FM�.����L8����Kz��F����#�v	��������X��e:`"�@���l�3*�����r�	SW�A3��!������YiwW�f2�L�XJ���$K�n�%����9����9�7�3@@0f/=^&���OU�+d��&_���[�������"��	:W�+�
d:�f���L���?
�y=<��"��p1���"j���)b���<��LA���I9�pr3�ZS>Ouf��
��hOR�fS���I�Wq��b�nJ��@�����,b���d�k�7��D�m�����(��
����Z�*V���~��z�
�Y�-�`�	��)�-�}I�Z�U���j�,0Am`-���$}93����L8����������
Z)�+9����2�,#`�$�'� #0��Z�V�W��
Fe�������o�
�f�)���fw2>��Sjw������im�����G��h�6�FCT�c�4T]9�mN��I��d�RS �n���m��@sBc;�M��L���"/����\�����v
KNG3�/�_�8�y���VS��><�!@�1P3�vq�
���#kU�K����"���N?�k��) ��=�! �����L��ID6�_����G����I�����<�wJ�+�:�0�~<��Q�������~,]�'�tp����^#]�!hR��m��"����+*�f�j�WQO�d,�E|�i������w�V�3�@fc�m���[%,�A�9���b�
���Bb������Hi'�f�v� ��1:]��F�k5;�X@�XL=��D���Fz�O��K=n������M"�]��:�������_l%�)s+�A�T��Srj�q���(�qD\A��C�?�����R����kI�qe� ���~1�k�����B��dVb)d�>�������$%PEY���3a���N����E6���NeX��z{r1:�z50���A:f��>�qTFO��.�e95B5D]| j��`���ov�-��?�+�Bs������C��9�9\�e|+�O�f�i��AC�P������i:��W()8���q���t���g�����n���#vl�?�}jt�^*}�L0tA�cj,�q2��Y(UZ���&$,+%�'
�������Mr������>�@�gT�;x_@���D!7�1�	ZZ����,��Gs��Oe�J.��k� `�040��MM(�5c���Q�e�Qb@K�u�cp��
l�*�4�(����_��c9E�P!��*�v�i�����h"����^�v1�Kq3jV}�13Lw^�'�]��>|����^��O!�'?�j�q�RD�Tw��G�n��$�\+>p�U�����Xi�g�������d�e�G<�Fs$�|��U��"b��9,���?saD�C�iwBl�j	u��g�������0���[���4Z��~�#$�Y�u���7�^�z/NN��?�����b+���F�N�����������o��V5/m���`�%|���N���3���A�K<��h���
@&`r�D���#!N2*����U���q�&�f��.��!8��u��5b�P�|L�H�������{��6�m�����@��s����{�[�1Q�H/�b�Q�!k��i��5=.�W��o��[_���������n�!�kY�qvHL|�����;�@�`�
�]�K�b�O�����!�e������n�����M���YcF*�}:s_+[0�P<uf.!������G��GD�k{�j���*��x�@�B�_�r~q6�i�#�ty3<��B��~�@a<��SAQZ���]� b�6N|0�f3�������KA��\�R�u����l7�I���A@������r�y###w���0l��T��o�L:Ek�8�S���iDa.���9��E2�l9=��P^����������E�uQ�Q���H~sk�Q:��7��*�f��{m����xJ��G��C��<N������p,*����v�rxB��O"��(��0R���vKY�b��6�&�}}3�X����@��2T�Y�.:���I���D7�r�aUCb����x�������	r��d���n�Yt��,P�P9�|6m?7/���������w*2�|	o��p+����+�/t���R�I������V�jt�0��F���~J�������g��d�#�lC�R���Z�"T��+����k���Iet�
+�6$�����L � ���l�9�?j�cG�q��
}P��pz��b����)Q�����c�W*�}y��f?K�S*��
D�7�2��	.%�,c���U\���|�N�<
�������yX����JE�@>�|����}-S�n=��0(�y����P���,�L���UN}%KN��,�v��b���a�<���9AKJk���"�w��q�������;3�����������d�c��l��#�LB��,�$�+Nb�~�Cae&�1,k/���V4�1�H\����G����Q���_Sq�3�����x�(�3�cj1$y�_Q��(;��_9{2�����$u�Ih��>�?12p�2!s��t
�E�?(�������N/~���#^�%Li��F����N;U��,��Z�f��JQ��O�����DL��]�����4?����qZiB1������$���^���d���<���s��X�;�@?��=���1������������W����~��3��\=A���$x�������0q�t�n�*W����4��L6�I�\hkZxP[�	�����;���
�
��4��T��_�H�jg]���KK`RU\��q�g�2@��.��9�T.az_��1\'lUD:7o��"U�����a��~�����l��*(��1���e��������r����"�qv~�;^^���(bt�]����O.�\e#�*����L�j��UP�<|_������x����o����]s�����l0�:_�%U*��  {��Yo���/
��s>�|����]#:Fuq��@��7\����T��*��T��f��e��,s����$����p�Xo����8?8���A�-���fS��M�^.���j�l
�|������gF�����g3v��������gh(���<�v���%�*M3�%���5���Cwp����Z����/oF��{hX���HG���D��k"
�����a������,�?�1��Z��m��
E�i��j��;)(l��R2����P��/������<��a�HY�(���a��->��GR$M���[�+���tj�m���\��n���2��2"�pz���>�L���$�L�:���xie��U�������+�.4����3R�/,��6 ��z��m�8N��Ym����}s���������t����@]!9+Ir�2g������KJ]R�'������|B�����1�����3��qSkK���"�u���A��=�����I�g�����Y1
{���'C.�;a��|!����X<];O]YF�S��*�OPQ*P}������3���*����B��X���m����V�����k���N�G��q�q��C��U^����W�|�:cu��cz����U��iz.D�/�Aa�����s��*�k*��z�z�u�C���r����=7*�
.�8n�j�lU��8Sd�r]��
���$I]�q�uy��I��-��;e�Z������
)�zr8+Q�x��f�%}���0�Ct;q��V��<�-r��KG?0�c�T~���"�<w���k.���GH�c��J�D�0�8}{��c/@���TGG�"����t�	�D,�#K�	�y^���-V6�U��������b�n��_^��i��z<���&fVz}W��qw}�%��q"&5 _7�g�:j2�O�^!DG'x`x�d=��R89��G
�;�r�`���Nl�x�%f0h`�z�/�?i���DQ���^
�k� =���N���(���
BUa�1X1Q���_$�tL�KR���@�E(��� ��ig�����)�E��q��[��^�a�*���5�,��&����k	2X*��;'�-��Q��.|��DM��:	`����@�EQm�KlTc�a��1!&�V�WUO��3�&s�
����]C��W	����������?Q�"��.����n��!���l4�e^M�NOK��2�sDM
�j/Y	�:9�>%�
5����@��9��x�3T�fF��*}�=�F���cW�����_���7�J�Q�����7+�_Q�o��E��S�[��1/�X��h�����Ng�i�x��[�8��������c=fK:�CE0��Li���8a�r�9ufi���8����`x�W�����`8��0?0^%R�J�4�>����%���F��;�{j�����Y��O��5�7�
{`Qq�>1^1��8�Q����<�c���#�o�\"�T/�P��������%�_���]���)�|�����`�����aO<�"����*0�/��>q�G�J�tti��u{�a�Ckj��0�KE����
��q*�������_���5����w�t��F�>���Q������o/�]���G��?T���t��	�V�'g3�Be�;��������*�3�l�~n��_��j�e�&�����{1�����4�=^�I�z2�y����Qs��q���*�S��{I��,�����\�jGa��?�V�I���
M�y%���"N*+�^�Y��
�
�HQDe	��``�c����<{3���(k`���}�8_��0a��}mT
@�Ue�;�[697�KC�\p
��6�9P����������A����w�LNzS9+���%K��q1	�L?��6�O.�;�V�5��68��+��.I�	��DH*��]o����l�j��}�`���ly�8p%m��]��VVJ"f��lHS"�<�5K_P��f�4�)lm�,XS
!�f�7�6��n��P�l�c����q��1=_��{/zo�N������7\�{X�5��qC�����������36���$��?L���*�Z<
j�"�;��r���;�{2�w�c�fsK�����%���
0�|���0/[v��sy�m �[�0��p��+Fk�m���!:��2��Uz����\N�@�Y�U-1�������8<l�yN��R7��:U�d�{��ADM��8�Hy���U�,i��<����!�l��*��j.]����l���A��Z/�#Q*���
Bi��3����8��jm���"K[g��i���jf)`���3��?/dxW�-T�������t������H����kG��S���K���D����XI:���/f:�/$�����0f��j,��^��������xu��a��_������M|������=P	/��0��Y������t���&��N]]
�1Ur(\�����'=����/t������Eo�;�cl�R�~>G*��G�2p�I�:%�,'Y"���r:����'j���
.��4e�7�VQM*�89���������6�uZ5E	��4�0j���|��q%�/��i�����/�����[u+V��*JL��kz��r+�D�D�z��5���# 8{�Z��=���]>�1������Z	?������`��gJ�j���������-�V��Z����n���RrT^N�����51_�I:��.;����m��2��"��@��K��
��r���@1�
	iZ.���TI�5�c���#���(�o(�����KZ���+����wxA��Lr��-\-�	���*1�0e%�+���:o�d\�T���3��L��Z82���9��
SW��Ib�+6Br)I�2�
�����`��Z`ecj,���0~PmxOW$��.�_^�b��1�����1�a	i����P9���S��^��p+���C����c�����$�+�A�8@p)_��5h�s����;9��d�9�L.=�d�Pd�*}��Qr�5f��_L��Q�7����c����{��z;��a/Qpc�
���JP%7F2�~�,������#&�EfHm3L���1�L\�^c��lw�Z`��v�{���A��p�#����`hr������Pv�d�g�;5���`���.�Z��&#{y8���*�b�����4��i��Q������V<
������}���N;�����v�����7��`*,v��I���m�n��59��/
�`r�$F:���j6��&J�9�#�� 5d2K�/��|��Kf,u t��zdo��~�}[�	r�8����Z���V��k��o�f����=�q���G��|�[�'�8}������/y����>[�77�h��+�����X�F%�v�����ox{}���^_����s�ez{}�w��-����l�O���P�n
OU��_������.�O<��\&o�Yq��qv�k*���W�-���SR�!�e
iL��[,G�$�F������},�n�#.��,����Lz�Wr��<(���4��}TM����,��p	:l���[�<Nj�ox����(6k�v�!�@�����hvw���PK��`�B�fPK���P�? 0011-enable-job-1-to-run-in-parallel-mode-with-one-worker.patchUT
uL�^L�^~L�^ux��Vmo�6�l������c����7q���
��b�B�$�f#�I�eK����Z'M�e��'R����w�V��N� �L���x�w�|�%�(H���d���|<M�	�"8���)�^�@�����\�~���p@p����p���������t�*��(�y)�@d�s���q8�U���z>���^�a8��@9I

��I$��Yq`J"IQ�V"�p���!/��;���(���"N��	I/������-D�b���?B�H��/h�C\�]Q�������3-���;���<G����!y���xF�n��4��I��d8�F�h�C���D�\�F�l����G��7�m+pBi����\T<��5S��E|]�E�$� '����=��h������4FM�A�������6�x���.��;���k/'�$UU���v���1
�.�H�@)�fuwP'cg<2��'�F1��R{���"z��	��)&	]SW���-�0eJ;���VK���?i���0�>"�n�f+L\���:����B-���p{{7�Wv��g��wKR]I^�n|`��C�������:�p7��n$Na��U�]
��v��v��_q>�!����^��"��)bE����S�.�o�=�+7����EX�
[y)�G�)�&d�s�n|0{�lvr�.%�j��j�G��7������O�x~���[�
[j���l��:�Fn�[-f<�{%��>YR����J�@��m�s��C�����A�j�f�U{v�.Xg���
;F���K
�:��$���Fv�
���
zIW��Q6L����Y��w
�=8�mA�%)*�a)� �����gm�����S��X�jI���H��F����Q��Jc�5����s�!�I���_(=
wk�Vn����[���	�6��h��J<JEx�oD���:_�*�L�58+qjE�9��E�kH�����q�yy������-��\�q�Yf�*�D�>��V�l�>h��s��
��X����Ey�����`�+b������&�ad��/���Dg+��&�|����V�����{�8^g��]���y���zG��j�/f�.���>��i���&�"�7����4���vY`��`}���9����F��+��HJ8���3�/-f�@�
���m�
?�[�w��%�N}U����^c���D�h����%r�;��0����oPK"Vd��PK���P}i���'? ��0001-Rename-sizeonly-to-dryrun-for-few-functions-in-baseb.patchUT
uL�^L�^~L�^ux�PK���P�����@? ��e	0002-Refactor-some-backup-code-to-increase-reusability.-T.patchUT
uL�^L�^~L�^ux�PK���P���ZH4.�7 ���0003-Parallel-Backup-Backend-Replication-commands.patchUT
uL�^L�^~L�^ux�PK���P�S��0��( ��\P0004-Parallel-Backup-pg_basebackup.patchUT
uL�^L�^~L�^ux�PK���P�f
�G# ��\�0005-parallel-backup-testcase.patchUT
uL�^L�^~L�^ux�PK���PI6�Oi�J( ����0006-parallel-backup-documentation.patchUT
uL�^L�^~L�^ux�PK���P[��G{? ����0007-converted-log-streamer-function-to-use-pthread-api-n.patchUT
uL�^L�^~L�^ux�PK���P|ez�
2"= ����0008-added-windows-platform-support-for-parallel-backup.patchUT
uL�^L�^~L�^ux�PK���P�s���. ����0009-progress-reporting.patchUT
uL�^L�^~L�^ux�PK���P��`�B�f ����0010-backup-manifest.patchUT
uL�^L�^~L�^ux�PK���P"Vd��? ����0011-enable-job-1-to-run-in-parallel-mode-with-one-worker.patchUT
uL�^L�^~L�^ux�PKt��
#99Robert Haas
robertmhaas@gmail.com
In reply to: Asif Rehman (#98)
Re: WIP/PoC for parallel backup

On Wed, Apr 22, 2020 at 10:18 AM Asif Rehman <asifr.rehman@gmail.com> wrote:

I don't foresee memory to be a challenge here. Assuming a database containing 10240
relation files (that max reach to 10 TB of size), the list will occupy approximately 102MB
of space in memory. This obviously can be reduced, but it doesn’t seem too bad either.
One way of doing it is by fetching a smaller set of files and clients can result in the next
set if the current one is processed; perhaps fetch initially per table space and request for
next one once the current one is done with.

The more concerning case is when someone has a lot of small files.

Okay have added throttling_counter as atomic. however a lock is still required
for throttling_counter%=throttling_sample.

Well, if you can't get rid of the lock, using a atomics is pointless.

+ sendFile(file, file + basepathlen, &statbuf,
true, InvalidOid, NULL, NULL);

Maybe I'm misunderstanding, but this looks like it's going to write a
tar header, even though we're not writing a tarfile.

sendFile() always sends files with tar header included, even if the backup mode
is plain. pg_basebackup also expects the same. That's the current behavior of
the system.

Otherwise, we will have to duplicate this function which would be doing the pretty
much same thing, except the tar header.

Well, as I said before, the solution to that problem is refactoring,
not crummy interfaces. You're never going to persuade any committer
who understands what that code actually does to commit it.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#100Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Asif Rehman (#98)
Re: WIP/PoC for parallel backup

On Wed, Apr 22, 2020 at 7:48 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

Hi Dipesh,

The rebased and updated patch is attached. Its rebased to (9f2c4ede).

Make is failing for v15 patch.

gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Werror=vla -Wendif-labels
-Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv
-g -g -O0 -I. -I. -I../../../src/include -D_GNU_SOURCE -c -o
basebackup.o basebackup.c -MMD -MP -MF .deps/basebackup.Po
In file included from basebackup.c:33:
../../../src/include/replication/backup_manifest.h:37: error: redefinition
of typedef ‘manifest_info’
../../../src/include/replication/basebackup.h:35: note: previous
declaration of ‘manifest_info’ was here
make[3]: *** [basebackup.o] Error 1
make[3]: Leaving directory
`/home/edb/WORKDB/PG2/postgresql/src/backend/replication'
make[2]: *** [replication-recursive] Error 2

Show quoted text
#101Asif Rehman
asifr.rehman@gmail.com
In reply to: Rajkumar Raghuwanshi (#100)
Re: WIP/PoC for parallel backup

On Thu, Apr 23, 2020 at 11:43 AM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

On Wed, Apr 22, 2020 at 7:48 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi Dipesh,

The rebased and updated patch is attached. Its rebased to (9f2c4ede).

Make is failing for v15 patch.

gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Werror=vla -Wendif-labels
-Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv
-g -g -O0 -I. -I. -I../../../src/include -D_GNU_SOURCE -c -o
basebackup.o basebackup.c -MMD -MP -MF .deps/basebackup.Po
In file included from basebackup.c:33:
../../../src/include/replication/backup_manifest.h:37: error: redefinition
of typedef ‘manifest_info’
../../../src/include/replication/basebackup.h:35: note: previous
declaration of ‘manifest_info’ was here
make[3]: *** [basebackup.o] Error 1
make[3]: Leaving directory
`/home/edb/WORKDB/PG2/postgresql/src/backend/replication'
make[2]: *** [replication-recursive] Error 2

Just compiled on clean source and its compiling fine. Can you see if you
have a clean source tree?

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#102Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Asif Rehman (#101)
Re: WIP/PoC for parallel backup

On Thu, Apr 23, 2020 at 1:47 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

On Thu, Apr 23, 2020 at 11:43 AM Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

On Wed, Apr 22, 2020 at 7:48 PM Asif Rehman <asifr.rehman@gmail.com>
wrote:

Hi Dipesh,

The rebased and updated patch is attached. Its rebased to (9f2c4ede).

Make is failing for v15 patch.

gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith
-Wdeclaration-after-statement -Werror=vla -Wendif-labels
-Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv
-g -g -O0 -I. -I. -I../../../src/include -D_GNU_SOURCE -c -o
basebackup.o basebackup.c -MMD -MP -MF .deps/basebackup.Po
In file included from basebackup.c:33:
../../../src/include/replication/backup_manifest.h:37: error:
redefinition of typedef ‘manifest_info’
../../../src/include/replication/basebackup.h:35: note: previous
declaration of ‘manifest_info’ was here
make[3]: *** [basebackup.o] Error 1
make[3]: Leaving directory
`/home/edb/WORKDB/PG2/postgresql/src/backend/replication'
make[2]: *** [replication-recursive] Error 2

Just compiled on clean source and its compiling fine. Can you see if you
have a clean source tree?

Yeah, my machine is not cleaned. My colleague Suraj is also able to compile.
Thanks, sorry for the noise.

Show quoted text

--
--
Asif Rehman
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca

#103David Zhang
david.zhang@highgo.ca
In reply to: Amit Kapila (#96)
1 attachment(s)
Re: WIP/PoC for parallel backup

Hi,

Here is the parallel backup performance test results with and without
the patch "parallel_backup_v15" on AWS cloud environment. Two
"t2.xlarge" machines were used: one for Postgres server and the other
one for pg_basebackup with the same machine configuration showing below.

Machine configuration:
    Instance Type        :t2.xlarge
    Volume type          :io1
    Memory (MiB)         :16GB
    vCPU #               :4
    Architecture         :x86_64
    IOP                  :6000
    Database Size (GB)   :108

Performance test results:
without patch:
    real 18m49.346s
    user 1m24.178s
    sys 7m2.966s

1 worker with patch:
    real 18m43.201s
    user 1m55.787s
    sys 7m24.724s

2 worker with patch:
    real 18m47.373s
    user 2m22.970s
    sys 11m23.891s

4 worker with patch:
    real 18m46.878s
    user 2m26.791s
    sys 13m14.716s

As required, I didn't have the pgbench running in parallel like we did
in the previous benchmark.

The perf report files for both Postgres server and pg_basebackup sides
are attached.

The files are listed like below. i.e. without patch 1 worker, and with
patch 1, 2, 4 workers.

perf report on Postgres server side:
    perf.data-postgres-without-parallel_backup_v15.txt
    perf.data-postgres-with-parallel_backup_v15-j1.txt
    perf.data-postgres-with-parallel_backup_v15-j2.txt
    perf.data-postgres-with-parallel_backup_v15-j4.txt

perf report on pg_basebackup side:
    perf.data-pg_basebackup-without-parallel_backup_v15.txt
    perf.data-pg_basebackup-with-parallel_backup_v15-j1.txt
    perf.data-pg_basebackup-with-parallel_backup_v15-j2.txt
    perf.data-pg_basebackup-with-parallel_backup_v15-j4.txt

If any more information required please let me know.

On 2020-04-21 7:12 a.m., Amit Kapila wrote:

On Tue, Apr 21, 2020 at 5:26 PM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

On Tue, Apr 21, 2020 at 4:50 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Apr 21, 2020 at 5:18 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Apr 21, 2020 at 1:00 PM Asif Rehman <asifr.rehman@gmail.com> wrote:

I did some tests a while back, and here are the results. The tests were done to simulate
a live database environment using pgbench.

machine configuration used for this test:
Instance Type: t2.xlarge
Volume Type : io1
Memory (MiB) : 16384
vCPU # : 4
Architecture : X86_64
IOP : 16000
Database Size (GB) : 102

The setup consist of 3 machines.
- one for database instances
- one for pg_basebackup client and
- one for pgbench with some parallel workers, simulating SELECT loads.

basebackup | 4 workers | 8 Workers | 16 workers
Backup Duration(Min): 69.25 | 20.44 | 19.86 | 20.15
(pgbench running with 50 parallel client simulating SELECT load)

Backup Duration(Min): 154.75 | 49.28 | 45.27 | 20.35
(pgbench running with 100 parallel client simulating SELECT load)

Thanks for sharing the results, these show nice speedup! However, I
think we should try to find what exactly causes this speed up. If you
see the recent discussion on another thread related to this topic,
Andres, pointed out that he doesn't think that we can gain much by
having multiple connections[1]. It might be due to some internal
limitations (like small buffers) [2] due to which we are seeing these
speedups. It might help if you can share the perf reports of the
server-side and pg_basebackup side.

Just to be clear, we need perf reports both with and without patch-set.

These tests were done a while back, I think it would be good to run the benchmark again with the latest patches of parallel backup and share the results and perf reports.

Sounds good. I think we should also try to run the test with 1 worker
as well. The reason it will be good to see the results with 1 worker
is that we can know if the technique to send file by file as is done
in this patch is better or worse than the current HEAD code. So, it
will be good to see the results of an unpatched code, 1 worker, 2
workers, 4 workers, etc.

--
David

Software Engineer
Highgo Software Inc. (Canada)
www.highgo.ca

Attachments:

perf-report-parallel_backup_v15.zipapplication/zip; name=perf-report-parallel_backup_v15.zip; x-mac-creator=0; x-mac-type=0Download
#104Amit Kapila
amit.kapila16@gmail.com
In reply to: David Zhang (#103)
Re: WIP/PoC for parallel backup

On Mon, Apr 27, 2020 at 10:23 PM David Zhang <david.zhang@highgo.ca> wrote:

Hi,

Here is the parallel backup performance test results with and without
the patch "parallel_backup_v15" on AWS cloud environment. Two
"t2.xlarge" machines were used: one for Postgres server and the other
one for pg_basebackup with the same machine configuration showing below.

Machine configuration:
Instance Type :t2.xlarge
Volume type :io1
Memory (MiB) :16GB
vCPU # :4
Architecture :x86_64
IOP :6000
Database Size (GB) :108

Performance test results:
without patch:
real 18m49.346s
user 1m24.178s
sys 7m2.966s

1 worker with patch:
real 18m43.201s
user 1m55.787s
sys 7m24.724s

2 worker with patch:
real 18m47.373s
user 2m22.970s
sys 11m23.891s

4 worker with patch:
real 18m46.878s
user 2m26.791s
sys 13m14.716s

As required, I didn't have the pgbench running in parallel like we did
in the previous benchmark.

So, there doesn't seem to be any significant improvement in this
scenario. Now, it is not clear why there was a significant
improvement in the previous run where pgbench was also running
simultaneously. I am not sure but maybe it is because when a lot of
other backends were running (performing read-only workload) the
backend that was responsible for doing backup was getting frequently
scheduled out and it slowed down the overall backup process. And when
we start using multiple backends for backup one or other backup
process is always running making the overall backup faster. One idea
to find this out is to check how much time backup takes when we run it
with and without pgbench workload on HEAD (aka unpatched code). Even
if what I am saying is true or there is some other reason due to which
we are seeing speedup in some cases (where there is a concurrent
workload), it might not make the case for using multiple backends for
backup but still, it is good to find that information as it might help
in designing this feature better.

The perf report files for both Postgres server and pg_basebackup sides
are attached.

It is not clear which functions are taking more time or for which
functions time is reduced as function symbols are not present in the
reports. I think you can refer
"https://wiki.postgresql.org/wiki/Profiling_with_perf&quot; to see how to
take profiles and additionally use -fno-omit-frame-pointer during
configure (you can use CFLAGS="-fno-omit-frame-pointer during
configure).

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#105Suraj Kharage
suraj.kharage@enterprisedb.com
In reply to: Amit Kapila (#104)
3 attachment(s)
Re: WIP/PoC for parallel backup

Hi,

We at EnterpriseDB did some performance testing around this
parallel backup to check how this is beneficial and below are the results.
In this testing, we run the backup -
1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

*Machine details: *

1: Server (on which local backups performed and used as server for remote
backups)

2: Client (Used as a client for remote backups)

*Server:*

RAM: 500 GB
CPU details:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 8
NUMA node(s): 8
Filesystem: ext4

*Client:*
RAM: 490 GB
CPU details:
Architecture: ppc64le
Byte Order: Little Endian
CPU(s): 192
On-line CPU(s) list: 0-191
Thread(s) per core: 8
Core(s) per socket: 1
Socket(s): 24
Filesystem: ext4

Below are the results for the local test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 0m27.016s
user 0m3.378s
sys 0m23.059s real 0m30.314s
user 0m3.575s
sys 0m22.946s 12% performance
decreased real 0m20.400s
user 0m3.622s
sys 0m29.670s 27% performace
increased real 0m15.331s
user 0m3.706s
sys 0m39.189s 43% performance
increased real 0m15.094s
user 0m3.915s
sys 1m23.350s 44% performace
increased.
50GB
(50 tables - each table around 1.05 GB) real 2m11.049s
user 0m16.464s
sys 2m1.757s real 2m26.621s
user 0m18.497s
sys 2m4.792s 21% performance
decreased real 1m9.581s
user 0m18.298s
sys 2m12.030s 46% performance
increased real 0m53.894s
user 0m18.588s
sys 2m47.390s 58% performance
increased. real 0m55.373s
user 0m18.423s
sys 5m57.470s 57% performance
increased.
100GB
(100 tables - each table around 1.05 GB) real 4m4.776s
user 0m33.699s
sys 3m27.777s real 4m20.862s
user 0m35.753s
sys 3m28.262s 6% performance
decreased real 2m37.411s
user 0m36.440s
sys 4m16.424s" 35% performance
increased real 1m49.503s
user 0m37.200s
sys 5m58.077s 55% performace
increased real 1m36.762s
user 0m36.987s
sys 9m36.906s 60% performace
increased.
200GB
(200 tables - each table around 1.05 GB) real 10m34.998s
user 1m8.471s
sys 7m21.520s real 11m30.899s
user 1m12.933s
sys 8m14.496s 8% performance
decreased real 6m8.481s
user 1m13.771s
sys 9m31.216s 41% performance
increased real 4m2.403s
user 1m18.331s
sys 12m29.661s 61% performance
increased real 4m3.768s
user 1m24.547s
sys 15m21.421s 61% performance
increased

Results for the remote test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 1m36.829s
user 0m2.124s
sys 0m14.004s real 1m37.598s
user 0m3.272s
sys 0m11.110s 0.8% performance
decreased real 1m36.753s
user 0m2.627s
sys 0m15.312s 0.08% performance
increased. real 1m37.212s
user 0m3.835s
sys 0m13.221s 0.3% performance
decreased. real 1m36.977s
user 0m4.475s
sys 0m17.937s 0.1% perfomance
decreased.
50GB
(50 tables - each table around 1.05 GB) real 7m54.211s
user 0m10.826s
sys 1m10.435s real 7m55.603s
user 0m16.535s
sys 1m8.147s 0.2% performance
decreased real 7m53.499s
user 0m18.131s
sys 1m8.822s 0.1% performance
increased. real 7m54.687s
user 0m15.818s
sys 1m30.991s 0.1% performance
decreased real 7m54.658s
user 0m20.783s
sys 1m34.460s 0.1% performance
decreased
100GB
(100 tables - each table around 1.05 GB) real 15m45.776s
user 0m21.802s
sys 2m59.006s real 15m46.315s
user 0m32.499s
sys 2m47.245s 0.05% performance
decreased real 15m46.065s
user 0m28.877s
sys 2m21.181s 0.03% performacne
drcreased real 15m47.793s
user 0m30.932s
sys 2m36.708s 0.2% performance
decresed real 15m47.129s
user 0m35.151s
sys 3m23.572s 0.14% performance
decreased.
200GB
(200 tables - each table around 1.05 GB) real 32m55.720s
user 0m50.602s
sys 5m38.875s real 31m30.602s
user 0m45.377s
sys 4m57.405s 4% performance
increased real 31m30.214s
user 0m55.023s
sys 5m8.689s 4% performance
increased real 31m31.187s
user 1m13.390s
sys 5m40.861s 4% performance
increased real 31m31.729s
user 1m4.955s
sys 6m35.774s 4% performance
decreased

Client & Server on the same machine, the result shows around 50%
improvement in parallel run with worker 4 and 8. We don’t see the huge
performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t see
any major benefit in performance. This testing result matches the testing
results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU
usage and other information. What we noticed is that server is consuming
the CPU almost 100% whole the time and pg_stat_activity shows that server
is busy with ClientWrite most of the time.

Attaching captured output for

1) Top command output on the server after every 5 second

2) pg_stat_activity output after every 5 second

3) Top command output on the client after every 5 second

Do let me know if anyone has further questions/inputs for the benchmarking.

Thanks to Rushabh Lathia for helping me with this testing.

On Tue, Apr 28, 2020 at 8:46 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Apr 27, 2020 at 10:23 PM David Zhang <david.zhang@highgo.ca>
wrote:

Hi,

Here is the parallel backup performance test results with and without
the patch "parallel_backup_v15" on AWS cloud environment. Two
"t2.xlarge" machines were used: one for Postgres server and the other
one for pg_basebackup with the same machine configuration showing below.

Machine configuration:
Instance Type :t2.xlarge
Volume type :io1
Memory (MiB) :16GB
vCPU # :4
Architecture :x86_64
IOP :6000
Database Size (GB) :108

Performance test results:
without patch:
real 18m49.346s
user 1m24.178s
sys 7m2.966s

1 worker with patch:
real 18m43.201s
user 1m55.787s
sys 7m24.724s

2 worker with patch:
real 18m47.373s
user 2m22.970s
sys 11m23.891s

4 worker with patch:
real 18m46.878s
user 2m26.791s
sys 13m14.716s

As required, I didn't have the pgbench running in parallel like we did
in the previous benchmark.

So, there doesn't seem to be any significant improvement in this
scenario. Now, it is not clear why there was a significant
improvement in the previous run where pgbench was also running
simultaneously. I am not sure but maybe it is because when a lot of
other backends were running (performing read-only workload) the
backend that was responsible for doing backup was getting frequently
scheduled out and it slowed down the overall backup process. And when
we start using multiple backends for backup one or other backup
process is always running making the overall backup faster. One idea
to find this out is to check how much time backup takes when we run it
with and without pgbench workload on HEAD (aka unpatched code). Even
if what I am saying is true or there is some other reason due to which
we are seeing speedup in some cases (where there is a concurrent
workload), it might not make the case for using multiple backends for
backup but still, it is good to find that information as it might help
in designing this feature better.

The perf report files for both Postgres server and pg_basebackup sides
are attached.

It is not clear which functions are taking more time or for which
functions time is reduced as function symbols are not present in the
reports. I think you can refer
"https://wiki.postgresql.org/wiki/Profiling_with_perf&quot; to see how to
take profiles and additionally use -fno-omit-frame-pointer during
configure (you can use CFLAGS="-fno-omit-frame-pointer during
configure).

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
--

Thanks & Regards,
Suraj kharage,
EnterpriseDB Corporation,
The Postgres Database Company.

Attachments:

pg_stat_activity_5_100GB.txttext/plain; charset=US-ASCII; name=pg_stat_activity_5_100GB.txtDownload
top_server_5_100GB.txttext/plain; charset=US-ASCII; name=top_server_5_100GB.txtDownload
top_client.txttext/plain; charset=US-ASCII; name=top_client.txtDownload
#106David Zhang
david.zhang@highgo.ca
In reply to: Suraj Kharage (#105)
1 attachment(s)
Re: WIP/PoC for parallel backup

Hi,

Thanks a lot for sharing the test results. Here is the our test results
using perf on three ASW t2.xlarge with below configuration.

Machine configuration:
      Instance Type        :t2.xlarge
      Volume type          :io1
      Memory (MiB)         :16GB
      vCPU #                   :4
      Architecture           :x86_64
      IOP                         :6000
      Database Size (GB)  :45 (Server)

case 1: postgres server: without patch and without load

* Disk I/O:

# Samples: 342K of event 'block:block_rq_insert'
# Event count (approx.): 342834
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    97.65%  postgres         [kernel.kallsyms]  [k] __elv_add_request
     2.27%  kworker/u30:0    [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 6M of event 'cpu-clock'
# Event count (approx.): 1559444750000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ....................
.............................................
#
    64.73%  swapper          [kernel.kallsyms]     [k] native_safe_halt
    10.89%  postgres         [vdso]                [.] __vdso_gettimeofday
     5.64%  postgres         [kernel.kallsyms]     [k] do_syscall_64
     5.43%  postgres         libpthread-2.26.so    [.] __libc_recv
     1.72%  postgres         [kernel.kallsyms]     [k]
pvclock_clocksource_read

* Network:

# Samples: 2M of event 'skb:consume_skb'
# Event count (approx.): 2739785
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. ...........................
#
    91.58%  swapper          [kernel.kallsyms]  [k] consume_skb
     7.09%  postgres         [kernel.kallsyms]  [k] consume_skb
     0.61%  kswapd0          [kernel.kallsyms]  [k] consume_skb
     0.44%  ksoftirqd/3      [kernel.kallsyms]  [k] consume_skb

case 1: pg_basebackup client: without patch and without load

* Disk I/O:

# Samples: 371K of event 'block:block_rq_insert'
# Event count (approx.): 371362
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    96.78%  kworker/u30:0    [kernel.kallsyms]  [k] __elv_add_request
     2.82%  pg_basebackup    [kernel.kallsyms]  [k] __elv_add_request
     0.29%  kworker/u30:1    [kernel.kallsyms]  [k] __elv_add_request
     0.09%  xfsaild/xvda1    [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 3M of event 'cpu-clock'
# Event count (approx.): 903527000000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ..................
.............................................
#
    87.99%  swapper          [kernel.kallsyms]   [k] native_safe_halt
     3.14%  swapper          [kernel.kallsyms]   [k] __lock_text_start
     0.48%  swapper          [kernel.kallsyms]   [k]
__softirqentry_text_start
     0.37%  pg_basebackup    [kernel.kallsyms]   [k]
copy_user_enhanced_fast_string
     0.35%  swapper          [kernel.kallsyms]   [k] do_csum

* Network:

# Samples: 12M of event 'skb:consume_skb'
# Event count (approx.): 12260713
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. ...........................
#
    95.12%  swapper          [kernel.kallsyms]  [k] consume_skb
     3.23%  pg_basebackup    [kernel.kallsyms]  [k] consume_skb
     0.83%  ksoftirqd/1      [kernel.kallsyms]  [k] consume_skb
     0.45%  kswapd0          [kernel.kallsyms]  [k] consume_skb

case 2: postgres server: with patch and with load, 4 backup workers on
client side

* Disk I/O:

# Samples: 3M of event 'block:block_rq_insert'
# Event count (approx.): 3634542
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    98.88%  postgres         [kernel.kallsyms]  [k] __elv_add_request
     0.66%  perf             [kernel.kallsyms]  [k] __elv_add_request
     0.42%  kworker/u30:1    [kernel.kallsyms]  [k] __elv_add_request
     0.01%  sshd             [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 9M of event 'cpu-clock'
# Event count (approx.): 2299129250000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  .....................
.............................................
#
    52.73%  swapper          [kernel.kallsyms]      [k] native_safe_halt
     8.31%  postgres         [vdso]                 [.] __vdso_gettimeofday
     4.46%  postgres         [kernel.kallsyms]      [k] do_syscall_64
     4.16%  postgres         libpthread-2.26.so     [.] __libc_recv
     1.58%  postgres         [kernel.kallsyms]      [k] __lock_text_start
     1.52%  postgres         [kernel.kallsyms]      [k]
pvclock_clocksource_read
     0.81%  postgres         [kernel.kallsyms]      [k]
copy_user_enhanced_fast_string

* Network:

# Samples: 6M of event 'skb:consume_skb'
# Event count (approx.): 6048795
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. ...........................
#
    85.81%  postgres         [kernel.kallsyms]  [k] consume_skb
    12.03%  swapper          [kernel.kallsyms]  [k] consume_skb
     0.97%  postgres         [kernel.kallsyms]  [k] __consume_stateless_skb
     0.85%  ksoftirqd/3      [kernel.kallsyms]  [k] consume_skb
     0.24%  perf             [kernel.kallsyms]  [k] consume_skb

case 2: pg_basebackup 4 workers: with patch and with load

* Disk I/O:

# Samples: 372K of event 'block:block_rq_insert'
# Event count (approx.): 372360
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    97.26%  kworker/u30:0    [kernel.kallsyms]  [k] __elv_add_request
     1.45%  pg_basebackup    [kernel.kallsyms]  [k] __elv_add_request
     0.95%  kworker/u30:1    [kernel.kallsyms]  [k] __elv_add_request
     0.14%  xfsaild/xvda1    [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 4M of event 'cpu-clock'
# Event count (approx.): 1234071000000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ........................
.................................................
#
    89.25%  swapper          [kernel.kallsyms]         [k] native_safe_halt
     0.93%  pg_basebackup    [kernel.kallsyms]         [k]
__lock_text_start
     0.91%  swapper          [kernel.kallsyms]         [k]
__lock_text_start
     0.69%  pg_basebackup    [kernel.kallsyms]         [k]
copy_user_enhanced_fast_string
     0.45%  swapper          [kernel.kallsyms]         [k] do_csum

* Network:

# Samples: 6M of event 'skb:consume_skb'
# Event count (approx.): 6449013
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. ...........................
#
    90.28%  pg_basebackup    [kernel.kallsyms]  [k] consume_skb
     9.09%  swapper          [kernel.kallsyms]  [k] consume_skb
     0.29%  ksoftirqd/1      [kernel.kallsyms]  [k] consume_skb
     0.21%  sshd             [kernel.kallsyms]  [k] consume_skb

The detailed perf report is attached, with different scenarios, i.e.
without patch (with and without load for server and client) , with patch
(with and without load for 1, 2, 4, 8 workers for both server and
client). The file name should self explain the cases.

Let me know if more information required.

Best regards,

David

On 2020-04-29 5:41 a.m., Suraj Kharage wrote:

Hi,

We at EnterpriseDB did some performance testing around this
parallel backup to check how this is beneficial and below are the
results. In this testing, we run the backup -
1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

*Machine details: *

1: Server (on which local backups performed and used as server for
remote backups)

2: Client (Used as a client for remote backups)

*Server:*

RAM:500 GB
CPU details:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 8
NUMA node(s): 8
Filesystem:ext4

*Client:*
RAM:490 GB
CPU details:
Architecture: ppc64le
Byte Order: Little Endian
CPU(s): 192
On-line CPU(s) list: 0-191
Thread(s) per core: 8
Core(s) per socket: 1
Socket(s): 24
Filesystem:ext4

Below are the results for the local test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 0m27.016s
user 0m3.378s
sys 0m23.059s real 0m30.314s
user 0m3.575s
sys 0m22.946s 12% performance
decreased real 0m20.400s
user 0m3.622s
sys 0m29.670s 27% performace
increased real 0m15.331s
user 0m3.706s
sys 0m39.189s 43% performance
increased real 0m15.094s
user 0m3.915s
sys 1m23.350s 44% performace
increased.
50GB
(50 tables - each table around 1.05 GB) real 2m11.049s
user 0m16.464s
sys 2m1.757s real 2m26.621s
user 0m18.497s
sys 2m4.792s 21% performance
decreased real 1m9.581s
user 0m18.298s
sys 2m12.030s 46% performance
increased real 0m53.894s
user 0m18.588s
sys 2m47.390s 58% performance
increased. real 0m55.373s
user 0m18.423s
sys 5m57.470s 57% performance
increased.
100GB
(100 tables - each table around 1.05 GB) real 4m4.776s
user 0m33.699s
sys 3m27.777s real 4m20.862s
user 0m35.753s
sys 3m28.262s 6% performance
decreased real 2m37.411s
user 0m36.440s
sys 4m16.424s" 35% performance
increased real 1m49.503s
user 0m37.200s
sys 5m58.077s 55% performace
increased real 1m36.762s
user 0m36.987s
sys 9m36.906s 60% performace
increased.
200GB
(200 tables - each table around 1.05 GB) real 10m34.998s
user 1m8.471s
sys 7m21.520s real 11m30.899s
user 1m12.933s
sys 8m14.496s 8% performance
decreased real 6m8.481s
user 1m13.771s
sys 9m31.216s 41% performance
increased real 4m2.403s
user 1m18.331s
sys 12m29.661s 61% performance
increased real 4m3.768s
user 1m24.547s
sys 15m21.421s 61% performance
increased

Results for the remote test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 1m36.829s
user 0m2.124s
sys 0m14.004s real 1m37.598s
user 0m3.272s
sys 0m11.110s 0.8% performance
decreased real 1m36.753s
user 0m2.627s
sys 0m15.312s 0.08% performance
increased. real 1m37.212s
user 0m3.835s
sys 0m13.221s 0.3% performance
decreased. real 1m36.977s
user 0m4.475s
sys 0m17.937s 0.1% perfomance
decreased.
50GB
(50 tables - each table around 1.05 GB) real 7m54.211s
user 0m10.826s
sys 1m10.435s real 7m55.603s
user 0m16.535s
sys 1m8.147s 0.2% performance
decreased real 7m53.499s
user 0m18.131s
sys 1m8.822s 0.1% performance
increased. real 7m54.687s
user 0m15.818s
sys 1m30.991s 0.1% performance
decreased real 7m54.658s
user 0m20.783s
sys 1m34.460s 0.1% performance
decreased
100GB
(100 tables - each table around 1.05 GB) real 15m45.776s
user 0m21.802s
sys 2m59.006s real 15m46.315s
user 0m32.499s
sys 2m47.245s 0.05% performance
decreased real 15m46.065s
user 0m28.877s
sys 2m21.181s 0.03% performacne
drcreased real 15m47.793s
user 0m30.932s
sys 2m36.708s 0.2% performance
decresed real 15m47.129s
user 0m35.151s
sys 3m23.572s 0.14% performance
decreased.
200GB
(200 tables - each table around 1.05 GB) real 32m55.720s
user 0m50.602s
sys 5m38.875s real 31m30.602s
user 0m45.377s
sys 4m57.405s 4% performance
increased real 31m30.214s
user 0m55.023s
sys 5m8.689s 4% performance
increased real 31m31.187s
user 1m13.390s
sys 5m40.861s 4% performance
increased real 31m31.729s
user 1m4.955s
sys 6m35.774s 4% performance
decreased

Client & Server on the same machine, the result shows around 50%
improvement in parallel run with worker 4 and 8.  We don’t see the
huge performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t
see any major benefit in performance.  This testing result matches the
testing results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU
usage and other information. What we noticed is that server is
consuming the CPU almost 100% whole the time and pg_stat_activity
shows that server is busy with ClientWrite most of the time.

Attaching captured output for

1) Top command output on the server after every 5 second

2) pg_stat_activity output after every 5 second

3) Top command output on the client after every 5 second

Do let me know if anyone has further questions/inputs for the
benchmarking.

Thanks to Rushabh Lathia for helping me with this testing.

On Tue, Apr 28, 2020 at 8:46 AM Amit Kapila <amit.kapila16@gmail.com
<mailto:amit.kapila16@gmail.com>> wrote:

On Mon, Apr 27, 2020 at 10:23 PM David Zhang
<david.zhang@highgo.ca <mailto:david.zhang@highgo.ca>> wrote:

Hi,

Here is the parallel backup performance test results with and

without

the patch "parallel_backup_v15" on AWS cloud environment. Two
"t2.xlarge" machines were used: one for Postgres server and the

other

one for pg_basebackup with the same machine configuration

showing below.

Machine configuration:
      Instance Type        :t2.xlarge
      Volume type          :io1
      Memory (MiB)         :16GB
      vCPU #               :4
      Architecture         :x86_64
      IOP                  :6000
      Database Size (GB)   :108

Performance test results:
without patch:
      real 18m49.346s
      user 1m24.178s
      sys 7m2.966s

1 worker with patch:
      real 18m43.201s
      user 1m55.787s
      sys 7m24.724s

2 worker with patch:
      real 18m47.373s
      user 2m22.970s
      sys 11m23.891s

4 worker with patch:
      real 18m46.878s
      user 2m26.791s
      sys 13m14.716s

As required, I didn't have the pgbench running in parallel like

we did

in the previous benchmark.

So, there doesn't seem to be any significant improvement in this
scenario.  Now, it is not clear why there was a significant
improvement in the previous run where pgbench was also running
simultaneously.  I am not sure but maybe it is because when a lot of
other backends were running (performing read-only workload) the
backend that was responsible for doing backup was getting frequently
scheduled out and it slowed down the overall backup process. And when
we start using multiple backends for backup one or other backup
process is always running making the overall backup faster. One idea
to find this out is to check how much time backup takes when we run it
with and without pgbench workload on HEAD (aka unpatched code).  Even
if what I am saying is true or there is some other reason due to which
we are seeing speedup in some cases (where there is a concurrent
workload), it might not make the case for using multiple backends for
backup but still, it is good to find that information as it might help
in designing this feature better.

The perf report files for both Postgres server and pg_basebackup

sides

are attached.

It is not clear which functions are taking more time or for which
functions time is reduced as function symbols are not present in the
reports.  I think you can refer
"https://wiki.postgresql.org/wiki/Profiling_with_perf&quot; to see how to
take profiles and additionally use -fno-omit-frame-pointer during
configure (you can use CFLAGS="-fno-omit-frame-pointer during
configure).

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
--

Thanks & Regards,
Suraj kharage,
EnterpriseDB Corporation,
The Postgres Database Company.

--
David

Software Engineer
Highgo Software Inc. (Canada)
www.highgo.ca

Attachments:

perf_report.tar.gzapplication/x-gzip; name=perf_report.tar.gz; x-mac-creator=0; x-mac-type=0Download
����^��i��Hr-���	�x]�[�����4K���S�4��'��`'��������3"t:��������35��S\��m9v��m�����w���u}}���]�?<�_����]��=�n�noo�������{����?���������T�t����e����������L�Sw���]��>9D��~���
��>����������������������������7������������*����W�A^�����^\�He{�WY�]5����?�}����N������������>�����)�^W?�%u�U������k�7��yw������Je�_�k\������Q�-��N�������>����S4M[�}�_x���-B�t�-������,E�~s��� Z�^��*�~���2����_
������;�,��Rw`��O����������y�m%�O/�(����o�����"Y#��j+~d�#�����g���Z����
w��_�Qn>���^���xb�������u"/���Sq�F���^��w��C[�eBG������o�O(��a�P���=<�|<�uJ'�$�����*Ei���(��6�y��"�����E���]0J,fw��m=���}�o�^�\�R���P���K�*��:t���
�K��p�>/e=�N�(�<=��:9��f�.�C{���yx~�{|~��o�8�-g���,����_�)�������Z&�t]}���V���2�D&��(������i�Y8�]���g�?������������]#�>]�y����:Rgq��8z�����1�<n�C���w��n>u��n��J�JI�g�����w�qE����	�_tZ��7d�S7h�|�#���{�~����kn�QR�M����mu���=C�o	���V��}?a�=����y��#�*����F���Q���3A�du�������Dmw&���o��;������WW������[��M�|�����kKQ|P0".d�7'�[�R7����	&�����"D��5�7$�8)E�1R�P��k�**Xg�i#�Mv���
g�{�����[�����W����l����������y���x��E���/�����������.��%���/���gB��K�Cw��b�+�?���t~n�Dv��"Wo�o�L����@���K�uE�2�j�����3�������e�'x������lOn�5��C����E-J������GKr���6�+�W��a�`.��U���t��Q(��	�{��P�!����������Z�{�������w5�?&�7����Z�?��y�\?��N�W�����^��5�j���+��xV�d�|<N��,ku���:y�2E�:�d[v������'HLs�c'u����c��3��n{��jkt'$8���]=9��#��#X�'b����#�xOQ������>�C������+�?��_�������,]d��G��D9����6K���_����\FrY�EU]a�{b�`�7���{���Lm�����]{<&zur=�rK�O��-�D�0����V'"9H\�2e~�L{Y�6O"����'#�M�b"�J0��o�?������Z��oQ<d�l�4C�Zt�U�W)~� �C���=���oQ�����J,�0�����!�n��d���K�C�~��}2�m*[8� s�E:�b~�����b��H0�4�m�p�aS^vUc�u=���W}/�\��n�:�#����c3:�0���[����r
��~�_Z��o��6�%e<
t��L������4�X��:��|?t�Mt�z�v���]�Z�u��Y^�����>�`h�EE���$�� ���o�{�9	�uL����(�~z�����36j^�k��B��d�V�A�O����c�X�0d��g�����
���)�[9�G�)�M�0Q��/QA����@-9Q4����-e��������+>������L#y�����q�H���e����GK�(�W;P&��2������$��]:�W������M�e���V"r9s��y�<�J��b�TZ�1��	��'�E������O"��y����|M�����^\:��;K^�v+ysa�h9}��+������l[��Engb����l���)��.�y���%�1�9�X-�����QGW��5Y�h[�P��U�5����p�����)�;���f!� aU6"�n���E#M��c��U��.�I-����{e��@}������������pb?h���Q�]F�2�c���5�d�hw�/�e%�A��#�^���%��r��Z��oM�Q
8����D�9\3*�%&��,x�4����=7��������/RZ4(�����h��[N�����{����<F��>}y���(a,��)�~}w���m��g�P=��z�����!���U[�u{=����K��x���<��m#@����H?/1����X�*n���������-�m����XW�<�����0#������__a�&F� �u�5����}4��A^JY�E&tV�*[|J]�j��U��3[�{t1�W?������/�@N����f7��P�
P�!J�!:�p���Y�N���W�=X�M������!�����}�6���&������O�4:e���
���u[�I�oq�s���Gn^F��sBb��,
�_y'F'	�)���8;r��&p��a'&P����"��=����.\��+M���e�L�g��A�P��2����2�Mw�co����&O������hw��{"��lT�b��PNG�(y���]����@y����_X��:[��`|nd��%�>
p��n%���ZX������M�B+(-���:O�y
8�I� #����@�/���S��v�]t%��G��A��;y���%R<Q���7�D�;��)������t�����i�4nI�Xx�0a��=��������l���G���H��=��
�*��L�b%�X�����Q��2X�����]���
R[T����?��C����_���������������3{��#��g��%�}����9��w����Mf�Y�Sz��{
xwV<	O����5��$Jm��ta�mk��Jk�l��3pc�k9'��6I!�-���~P�W?e(�BPd_��������.TL<[B���~�>�%�O�/D;�05S���u�=M�M:r�Fs��'�!4/*�C���uN�&��tBA:Ov����d��@���ZZ{�kv����t|��A�v��l�
�]�����t��<�A
�RU��,���V��������n_E�2���
$��N��Kj��Xd��K��h��zI��u�R�D�:�c*���4|�V�����r�������/�$KF��� �CV�?q�@�n�E�Z-*	0
��I��K�'���'�hW;�0����������_�B��v/�?D�{#�g�u.����Z�^���}�c,�Wq=(�<�Mahj�L��4��w���Z~�"�nl\9�/��T6L���O�J0$.gx�FY�\��w�2O~{�K�\(���f�w_��2�wvI0�h1%N="������<y����xo}������;yY
�������2@�ScB��P�������}�DG��a�WR��7\Iu/XZO��U���g�p9)D^�HT�J��%��c2��"M{�����QT����N�����W-��J�X����,��u,krJW��4�0�:��wd��P�JzQ~����H4��_~��w^Wty`C�V0YK�;�K����u v��:�zN�5^��
d8��U�����8MfE�,/����]_+��Lo��k.�.5�hC����e^��-j���8B�����Q�!��e8#s�_��-�en��RYJQ���K���\�MF�d�ww;�;�$�=�C�j%
�������	��Y�}��V�G������+����@��!��Fdd�NUiQp'�4�g]���7c�h+������i�������;�Y�����Mt���8�	!�Q@���<"z�~B:�WSr����&�V�����% 6��r�s�����|�h�����,fx~��(iBnl�%�h4�A1/y���T�?����d?�������T*D9��r��^8����L�]��x+������t�?(�bg
�]W���cI�d�����=N��o�SI	�B�O)�RE>�'p�>��C��e#�c��Uv(�s�](�$�Y����C�������e�������,rO����}<a%��Xe�2��|Oh��B�����:�����Tl�`b�P�a��P_���N�3k�����d\�+;T�������������8���(��Y�������k�B�%5�}~�0��z"w{���������Q^Of0������A�9���F� Id
V��'��{����R�$������H���a�G����<�7xjC!�@��,f��0`�+fGV:�7�H���r6��,7��2��<��b8���n����+��X��a��9�[Jn�f�+2�;,	��1Cd�ai�^~�5s����#�]km�xvn��^����G�3�z��5�����`�Jn��<���&?�"�F$�k��R�]��S��kB���X0���_����������{h����������h��Q7�+Dl�w�iZ���v�,�N��Y��S�/�x�"���h�@���o�b�D���|��$&g�|x�+���,��<59�yy&����N�#+9	�
���j�O�u�nfxH��m�j9&E��]��`K�!~������kzn~Ek*����g�����B�i+4q����O!�pw�'����	�������:Rg������hR��d3�������������\1�����d�j:�����_�%�KVl�k6j5o�A�3���Z�<������s�(G,n�;�4�����0��Z�w��qq��Th�CI�+w2��
���D�M$
��Kzb2��v���.y�Q�N���Q9���m����@*�4�&��9u�8���b-�-�Z*Wg�b��-(�^L�`��e�%QV6'���	���Kw�[��8����k.�
,���������|C�}1O���~����Rp!t7k�>���m%���r�J�l�L��v1<���^������p��nb����R����L���*�QN�G�*��d��]:xh��~S�-zU/��N�����,����e[V�Y��G������,�5�����B�oH��m
��HE��q���A��Mj%�n�w�
��;T��@,��J��3�^8����6i�v�.A�7R�2u:�oxCj	��k+����$�\�y�?N@���J8t�:������jU���e���4�7�[�]�[�v";ka���>�����	�R�I�Pniq�=3��3S�~zp���F+�����s�BH�2�b�x�c��
�������#S���V��/]��y�-����-��~�*) 4�
��T����2A�.leS�	8���A����=�#�P�e��V8,������+p�$�����#&�P�5����E�3bg�M�|�]z
�l��_�(8rb�$'J!�D��������r	��@�����/<OM=b�pI��G��'�i����������wu.+���~���o�d����p7)9`���?�z�� ��H/"�*�1O�������.��P� 24�L;�w�a��qm�X		�v8yCB��Z�����/�����0���+��-C������t�A�u#0s�!���"�����3�>-�$9�>9�6�CW���_����}�L���D�����E+a�?�u����DM��k$y����xF
�mUE"_Cm�2�D
����>~�"�s�_��J��f'_>�C�!��5h��W5}eZw;*��!�+y���p���SCuJv�wR9�&�E����l�A��b���U�W������uA�%����SKL��j�i�	k���?�}}���.���sB �n�}�:����yP`���?Q9[JV�������;�\�T���uV!��+�93����>fn��*^b��P���X�b����1�K������5J�(+�o	�]{T<Z��q-��a�]���;p3�	��y���$���(�!���X����*�*�He=�Y�E��qZ���j�h��0�D��9���~�O������X��G�X����d��u�P	�ef6��S%�����A�����]:2�f-A��y�t�TC5t�W>�0a�����L&��'�Ag3o�&��������)��{���G�Na�<�; ���{�FSr^�������FIS9#���hMu����	;	�$w}���T���
���T�.�=��cSwnA|�)��v�aG�����1�M}������������G����M� ���Y��[���^���;|�Y���	[iW��P}Q�i�A�)������N�P�4�(��|3Z����U7tF��m�C4g��\�7�}��P[?����S�#$�C������}q��G�d�1�m��=	��[3�:1��|��_}:���8?����%��(V"-�r�D{8�l�u//���	�lH���[�B(��<&��B�Y6�[���"jsa��l�G�*�a�
�d�I���T���n�������W�i���H�d�z
YxW����v9?>[|asFv"NB&�9Z���*�*��k���4���o����>�d���P3s��2P86����ePS���8*M���y���g��5��#��)��:I+�]U��|���xT�=J���)���e�����'����|�S��%���9)K}�0jH�-;�jO����������,�I�������1�����d*�I.��a>~�}
�.+a���b
%v�A�g�WC.$/���� ������W���$?��l%���X[aA�������G�Ey������E�������C#S��U�s��!�&��>0���46��B2��r�by��'�&-�\�YW:��y��-�=�����/�l���3��WIp����E�"yv����IS�������V�����2�����n2�q�2)���.Zw�����Wp��������a����K ���!����>A�������y2���[�+q���#�'��W�Y9��M�n�����+!�������i{'��s'��������P"�����r:n�VO7�#�4����6@�)�(�����".�O�e�]��Fc�����n���$6\K��;����h��	���5{D9������2�_��^e$��������}�CD0RuR�l�r�M�4�7���K����Sbo^�	7�Y	L�*j�4����S�q����>��Bi�Y�����T��I����N�mq���7s�v��p(���{#��fo#0Wi�b����lo@-����-��MM���i#�6wt�@��6@����E��*{���6�v��/R��T2��>�F�����C�G��w��k�q+��q������2��E���$�C/���N��.�u�U�g2�A(�O�b����lk���[2/�9��(��NYg�A��6�K�#$v�?������~�}�����v1���X �S������C,�9�����V�?��<x����qa�d�J-��M�"
(e������� a<I�h����!����}��C`!��@���?������������V�c��c��D�h���ue��BO�%�������d�W[{��*W�����DSpQ���(:��W�	(@8�	����8kYkdm�H�mjw��m�����(��f�U�^9-��,�M`6���=�{�u!���}��������/���}�����CY��X��1$���<?�������I���mR���-����i��J�P��k��6�)�'�1V����i���]����?���G�m_�aV������7��*Nc���/Fue�5���>������b�AW�7PA��i_����X��Q���Z������6NX����V&� ��x�������`+�w���BSxw��������R~���m����a�����9����Y9A�������i!��Ke��
���	^>��$�7D,
��!�3wQ��F��B\dl�1��i1���#�t�G-�(��7r��9���d
8�%Je�i��V�&l�O�����������	3��o���yK�(����z�9����n��&���%i1��������uY8$����E��0a)�,�������6Iv �������Mv9��$�n6��<��y�8>��?{�]@c��E��{����6+x�A������j�b���pt}2���Q�M�C����$���W�6tiT���d�<����[K�����Tn�3��K�n����oPj�{���&^��!��t���������#�������f��b!����w|��q�(dc�^K��8b��J����:7�e	����a��UR:����sY�
$����P����[�7-��5���Cv���H5��)&�&�i��f���k���C����
�@����6�.����SLIw���� )�����V����r��sQ�������6�����V�=E�������I��8=�!
9K���/?���_ ���,w��w�Bs�]�	�,�?��e��]��������JQ9���`���V���<�m��?�I�Q[~�~R�@{_�L��>�\��
p����nDX���r���J����������;.�7�-�����?_�!@��!�@Zn3`�!��(j�n�Q�{@����������S*�z���m�����d�����������h���%�I����
�edUt�z(R�,B�iL��I�y��Ri��WF*���
����L����J��S(�cvV]��y�UtxW+=��H�R?��z�}t-E���]S�5)�g��v�2��-����cQ[|���`L.�F�T���"��ZHh�=�K���}=�6]��?�Bgg��S"@����i���������E~��^Q�J�Xp%f������u�P~?����	b��H��5�@������[��E�&,������=8����FFG'���y��9�S�t�E�y���I!i������M���cx�����x�
���V��{n
W��[":NG���3(�������8Z�h=pH�5�d���"%n�!k'��Jk�P�7^��k�C#�]���vkZ5��?��
P�wu�2S�S�j�}�+�
��N+���N�|.,A�^�&������^zd��s�i�����yh�$�����EW�E&��7j
�e�b�6��6�r�tY������,N���#}�1�����.�5�S�`�M�vo$��=����wl�Q���'�&�a���5�i�Fk?���'+�D��:%[�VT��+#���%��7���uk�=x�zJU��N~I�-�U�������7���_�,�e�������xQ ����@s��!I����� L��n�����T�X����������!{A���f?�X�h������a=EOwNFE�����@)����(
�KD�]�1�[:IH���P�bM�8�W�v�Ow�b	[�`��
�k+=<Z�k��[qE�U��M�z ��S�iiy����(���q��eq����8�z�SEC���R^u��Vg��+�~xw����70�UOf��\���94���eZ7[8����=��
S�)�;9�GR��{��rxqs���6�K`�7Ha�����C2mE^����Sa�c��-r��h���x��?�_��%��S.���r;a����dr#��;����(%z�4,��d�[������'��bH�m7��a)��<��H?�sCE����_����kIh��^{��Uj��\m�����H�����Up	�g����m$����J��$�}a�Y���fn���,m+��9���$C��6�oD?�������Xm��L�v���q��0dl��P���t�8j��mkn��V�'�5���t�`��ttQ�F��EU�Q���|��{!g�Vo�+��6
l�����G��'a$eo��?��)HT��KI�l���
P��P������@�m����dV�;�
�S���(��p����
�)+�?�|���>g��_��-`!��}���'8����Ja�����mrd�L��J0��S�C�������U�m���du���i��w�|v�.�%�(�����}1Q����B�0��0gz�^T���!���=%��!��A
!��P�M�=����};c�����j������Zh��]!�R����w+[w[
���Qq��#�H�l::����$B&*���M������$y�1u��@e�z0&��_��QR������MCT��
2E�*�yp���K�"�4!4O��B<���b���T���������`�4���ab���Zs���R��?�!K;u�����9H�;����*]�(��X`�u�\������sf�r���5~�m��c��p����5�@������=�<��k���$�: u�yb��;��b���N�t���������������31��3���j}V2��[���?��Q���
����w��a��d�z������L����y!�����]�?��� �ZG0���pa����d��5w.��,C3���F�&��3���tS��?����fz�������Y4@VZ����8F�I�,��	�v�
�m�wk�B�8Z��u�EiqvD���.f�5hH2B�if"-@����k���V���t���E_\�.g��4��R�N���v��j�
��:j�u�����(P2�^�F��e�A�y���7X��������ps���<����`������R��7�D�eSp�����#t8�Y��U!t�����L�BXHESJF�?�&��Dz�Zs���0��	��
`0@G[��8�D�Z�1!�@��L��
��O�LKsk+�\�A(b_)��}G^u��_~�z�_|���S��	���JD�P���y��&2��D����*6b���:6Ew��C���bE�I{+3���V�m�[-���uSU���dd����[�6G�l���rE�8��P���
%E��AH��c}�y%��0�R�857�!`4M0`��C����n�xv[�A=��?A��o���t�?���9��T�&h%l�c�%�U��?��(���������xJ�i��=��Y7��9f���{g�f��Y�z=.3�VK=b>��Q �:�Fl
),��^s���+�g4�	/#S�Yt'��������������������,9�9��L�9Q���:�!�@��6�����6}
h�;��'����Vj�O��?>o�}��
P����������l.���\�}a�gA�s/���3�'����2��Q����h�7�e��w`�������[�x]}*�1#����`�Z�E��f�
�E���=f�f�!f��J����U�?��Pm�~�����R�UTy������M�Y9�`���Ie�C	z�Z��;(���J�y��T��Z�%��Qk1��B��X0��C#.�
�*�3��OV��OJ�~�7� s������������V���	�Uk��h�0�C��G����ZP�����n��o�D>�F|��=_��dz���~3��������n�)a�=�\_z���j�����K`\X�bI[W���X���eN���.m����C|��Y+2�B15u7�7�786� \�������WI�/������n�����D�D�|n�YT>��x7�^4o�z.�<.lkax
��VpSB98Hu�^5��*b��e��~Uw{�����"J��=���j9��=�DzLx)m`����Z��Y5�
�o��-�9X>����h�����}=Vv�H��~�5�������o�sR)���)j6�����h�@*.�iI7��64��>KT��4��,G^����2�a,��=Dc�N{P�(�2����Q�Q��`���t��0���.�z^���)^F�c��q����Zc�>@0�8��[)�&��
�a�Gs�l����j���v.0��{j<��5�F�[��6R����{���R�� K�����S�����:�[3�|&���WZu/��e
�J �p_���6�W��/�8��90��6n4���EH����Qo[wC�D#'A]Q�]7w�)@�z�W h���l,��[�@;�iAAA����Y��?�u_p��������9��]�WB�h�I����<{U;�R�Z��b��9i��N���m������%Z�,�cHy�^N���!��i�tqap��r�D�x��k�g��P[�	<ajh��-�h��O"��1Uc��~5��Nq yG_i������[��
�":!j��>lL�[���y���@ ������4��%=6�-�2'��lC/��������Fw��l%6<�����m��Y����e����Yy���R����y� ����r�Q�����__?+o���m��8� ��h��i.����1�'����,{��A'E��,��a#�8�3�Gk�������z�wv��@M�1�_���ph@��OL�g�w�#��&@�
*�=L1��9=������E*GRg��%�����N�����c�	l�/?�u���]��tp<��(��R�b_)W��!5�2��\
���F���?��24���/�����7����xA��
L�c	Z���^���������e�s];��*���_��R�������?���Q�������8��� ���������L�Y#8+U����m'��=���
$G;��
r�Ge���s���H���o�V���.�6t���;sxm�����Y����vKu������sOL�I|�pK���m���(��;���q.���"U�O�G�3
g�F}���_���@�6T�J��:��0+�]����z��\�������U�A��|��W���m�x����_S��n#�g�8c��(w1����v�Q���!1v�����:P��RYu�[��9u�a����nnY�+���������Y���.�Y>v�I��T��������v���% j�Lz}�]nQs�*�O��
kN��1`$nB ����@q�����Y<�g�Ic�����]z�
P?@~/��.���p�M ��}7��=��<���^���9�������qk
�����n5�1&��Q�}�Nk�9����H���v�@�|H���uMio[_�4$�4
~����
����%�W�x�z���G�~%����/{��&+
����*K��_=�c#�:�����~6_�������&����JE�h�R��?��t1�]���"���{��z����fG.A����{*O��|V�������������O�P����j���	�jh���zX�}yc��q���	�z����Z#-�R+���Y-��P���Z`� 9�u��&�!���OD��jA	�k�V�fdA��G�y��s��������
�k#D�Q�^���V�~L;_�c�H3`�
�z�WC���aA����vuC�H�����2�_���.�*"�[r:��8yHD�K.])q���u
���MB��q
�=�����	7������4��C"&��f���
�����e�������n����3�i�Fw���gh�������#C�b�c��	�#�/>V�\�P���J���jmg5F�������"��������d&)�AR"�������Ar�2�-�<TQ<�M���k7��3�����t}�6w�����	Tu������7eX�_�@*�n�K�Y������tI���c��HG���s��ff��
�z;��K�$����L$$�fu!�>q�8}���S��Gy�	Pr;�K0����Y7
��q��8����&@�\�	$o�w�=�3�t.����#��m�Q?l��3�|��;��m:{���D91E4��L���{a�����������G���{��Q��c�b��z{���FE�Gq��	*nR��sO�m���"�m/��!��g������L��	�����^Z��8T�A�\]!c:��x[�$�.�
'^���h�����]��e}��a���8�p�����Rw��	����H�H�DX���v8�����\>R�^
�&��q���R��};�Z�,��'���`�T�ur�\b�)��}:�7�o�������\="k�z�6R7!������E�t�=����q�v�����HV��?@?S
��J&��0o ���n����L�J��,�����_3���������g����d�n?.�,����K��_�����#��p������37��
\�����8���C����vh� ���{���Mr}{=���^����;���)������	[2u]���c0�g�?�Y���ZJ�,"�6�0������A��I���
5���-l�aQ�4wP�=���
cSH���(�0�\+dw��D�j��"�'t$��g�9(��-k���H��n'�+���fji���L$����3	||�Y�l�k�u
Wsv���"���b�:��fG�����ueI���3�:������s�;����H��������7��
1��c_��r�Y�8YR9��u\��A~�d���T�&��p��	'O&E?�l��������t�;lxu�~R��O�Ec�������G���F������F��5��$���z���q�D�H�hm"����������5��	"�*)@$%d��Zc;
E/�J�����k�Sz @�<���bo*:ay�C���C!J�����H���G/R6�<F����^P�'b�,v���=;.n�'P����=2co����vc��v�<���G?�C^,-JLr*�:	Y��h����q����|�0�\�}�4acU��8��'�& ��N�C�l��Zy��c�V���E�[b�4�w/�����c}��pl�� -���G����@��-%��m�����H0���<�n,��Z���C��$�P�����V���|�?�JDO��GU�0kjL$�-f�h%����?F�S,������x&L�HxJ���i�I�xQ�k?
1smJ�oJ
p%+�?����O�2;�1�K�i�M����N ��	A��A�&�@����`c�E_�<'=q��	C�$�W��.��a7���_L��uh�/��H�P�!�D��PU�
C�S�`NH��%��X��]%�������5�i�$$]���.�~�)
t5��������K����=�C�Pk��������h�����q��I%�a�g��a����}�V��R��ZgNv���#oF�Zn�W��h@
�����*(��������Mk��-�l�$�!���7ngW6��EN�gx��Z����������]7z��������tr����/Q�KSH.��&=Ry�h+!�7��,P��1���/���%��������a�n���ZFy����=4�����Yo�8��F��G����Y�������&���\�h2���>m�Y�W'e���QZ���\�.�>�2W�o��*���%�c������������� �������F��90�C��4D\�5lM�*���C:��.�M��p�
4t7)st�4�����q�B��?V��8k�8�<�P5���y����r�����T��w��G4����P������-PTT?���k'm5���Lcy_��{]������=Lt�!C�[?��,gxc�U$Er0���$��6��p�97���������l�����w�3eNK��=��#�@5:#�vD/��
���D� Z���A�E�(��"���aN�o�}{4����������]��{� 5�*^`�������O
�;�y������8u!�!�t�w`z�N��y�VD]oK9/2�W�H0�P��Az��u0��q<���X��YumS���s�������f�{Q��o�c����/D���8�t����1��������#�{����ME��Z��W���+jy4
"��tu"��E��3.��*::��W%�-R��3P
35c��V:�i �B�`
��1�?�:�F�6�r+Dl��XeI���g����Ym#Ne<�mJ��P6���^b�b�$���d&uR�^U���P:�������GID3�E��;N�/86'��qpD����6������V��O$�����S���h�bN���8;�)`��^���^�,�����Y������iG~a8d�MZl
� �y��iT��|4)f=\� ���va�pp�y�<c�b�4���(��
z�?D�|�'���U��sZ��C(=*X3esh`c(X(:y�'LBnf�:���9 �8����GN�L��k����R��rF��
���$~����I��q$``��&k���N������%�%���!��h�T�����=�I���
��Ik�?c����$����t�8����O&&�0m�Q�}L�0���5e�{1X�V������@�Xk@�B�rLTw��U"F��b��If�Z�����/���`�.Oe�
��1�E�Iu���:+@Z ��K���}8��.L���H����s1!&e�R�����0��	w�J����Z��a�FBY�	3vS�\�K7y)j��u���8���>M44{c
U<>�E��m-�2�}��5&��>2����w�x����*�X|���d����EJ�"��!��hn*".$���������+A��a|�e�X}��\W����Y����@�=v�_P���D���q���]��`a�#���1�hhD�'���_CBj�( ����!�	���+��t�V���6���n6u���
2�kx���K#A�f�L��2
����1j�O��QQ!3�� aM�5���6	a�QQ���\�+K�����C]�l� B�z|�
B��}9�m5�0`*���>mq<1�o����y\�?i�<K���A�.�
q�4��yy�����p�f�����|���������B��hNA \>����"����*fR����Q����mb���
dA,���nS	����+
�X�^�N~�)��c�#����u�1,���6^h�%]>�,N��v��V���w�:ue�@����3J��6zr�b�@�[=Z��
���7�9�J�@��t��s"3�	�g��&/[�=�6y�R��r��K ���(�f����a�u���&�_�[��X��i��=������,~�����#���no�M�Qv{�������[�������������nf(��"�u�;D�:��L�����(��S7��|}��?�m,�?����y���z�hT�� 2�rC�����@��V�H&�j��n'E�9�`���4���f�\w���,�5j�d�KW��f5�#�SS�b��+(�������Q��)�zE��������W�B��>/�����&�����9�{�4��m!�I���U�,��H8P3O���6lu�=d��z,d��M@�H�A��2[�X�����O��q,�
jH���E�L��H�GzWX�o���d�,2&�8P�����y������?��N^�t)������H@�p���b�������Xa��b]�
�w�42����7Dz>i[�Ypa�(Vv;+���B��f���z-�x{���o
s��� ����S��`
i�;`��z.�#X������"���@cG&�G����y9��M��?�f0�@������2>�	�
p��L��� P��7/}^e�����j���kSx��h50jcd����Z�Zh�����6�N�1������@����:=������.f��jO��&���h,���4������n�A:�lx�?��2��:}�X�m�!��"\���t�F`�����Z@�Y8[������(��Asu�
�������yK�?*L���5h���q&�!"��A�#L ������$7]b��F"����zc�3)x�~8�%n�F'�����8K�,�EC��-�V�/L�MG>����vu$|+���H������y=zF2b<� �%�-�����H�$�-BU{�t\�����[�0�'��<����$M2=���f3�?�Et��*���o��s��1��V\s��7���j ��US=�di(���~�M���z���KDu:Aw|7/�  [6���|��������W g
�b^�]����N���������P:��w��ZQn��������?~���H��y3�7Ng��I@6�*�$�6��=�i�c=�g�c�4�uD�N�$!���s]�d�g<��x�P'��IC���'�BX�P��'��
���Q����d��K��0���}���
��*���_��6��������;�/+�_�h>��������'����ZCY�'�O�������!��^�����;��~�W���:���d�������������O��V��?��Gu���!w%�_�	0
D�V6���!/�?��N+�_���eh
����E��e�����w�������a�A���m/�o�T������TK�3�p���dRe���R�~���~�P;xQ����(O�W���2���D�����o��c"}=(����+:j��?���l�)�����j
�y�,Y�����g��W1�*��3@
�����GXa���=��Gq�2����!+��Hs=]M�^Jj����z�Y���:�|���g]���<��%�
<#�5&�
b�:��xn�1��0��oX?i�G���&A�$�a����+	�����^�Z!�����7�P'��`�E���;ymE��H�D�
;
�#�W�yh�����q��-4\��}�5�jw�m�v�K7mb�z]���	�l4��Zj��������}�����jUC�j�(������8<&���,�L�/�P��"y=o�\�x�d�,��k�4�mp���:;;#��?�o����Lm���x�xPQ�1�����&��H��0N$���
��XM��^��4�&diD�="�����	D�XQ�&�$c�wp+�V�2kGP�
Y�oY[F�|���i����?Z���d��1%�,y+��1fI����N���2�o�����	�CuQ��du�*Z�I���?_���<��?ub�����C�
q�sw��f!
�;�w�"I*&Q��-�iH ����\������U�Z�@�j�k!EJAy�MQ^E�=G
����8#�@#3OBq��u���-�G���RP�S��'a�r�r����1�b���� ����v`��L1����6��}���:�Iq@�����rdT�����@�NR�D�\�?�c��>$����C�����M@�/�.��Oz���&�L"��H���6����`� {�`�u������q��M�����'w;�(�dv�����N^��H�����R<���L������5e_^�m_�&���[U�h�����v�av�)��aN��,B�U��d6�������~Q���L�(�9im2L"��'6�����k�h�)/K��p}U������ Ll��"3�>k������&3�l4'�t+)����Wn�9'H��]�p�E<�1M}�(����BY�mL@�9?F�����$����&a���|z�?�$Jh�>�z�?��n��dev�?
nI�-�d7oZ����o9��������~	�t�K��ls,�!�Mi�X������S�&dc�0:���LB�Qi�A��q����T�?�kT�RF���8�k]
��@�A)
u���u�Q�����]���D����fA���r�b�k��I�`��=N B{���l��.�Z���gm�3!�c��:�j��x�G����R9"�*�|�����q��)r|�U�NE�
r� >�-A�����+���9��;C�f��B����\G�t�95z�x�_�n�����ku���O��n_����(�����|D�~�JN�x(���>LY@����[����Oy%���	������_�5�_iE���Q�^����Am
�j���lb�����9�^vPw� �n$��w�#u�Z���OOf	�!I�u ���wp/?��	t���#��U|V�k@����d��x�0&�@����
���P�����d�7P��
�������v=��a�;zx�
�q�y=�l�p���6�"�������a����EZ6P��WK��(N\��Y4{��6�~�v�����XHW�H>=�^�'Pz{�8�@�����C����v�?��8}���H���}�;�O��o��m6[G��~i'��+Oe'�x���Y��s� � �?���*��8�����=�����fa�������~jH$�����o�J������Q.)��C�4�
Z�4�.�+�eD���
����v�c
���M'����L]�m���I�����ga��P2[[:��x:��
�Z��?�I�W�{�
��M�XH�I:����Pk�~�JQ���^�
�H�~*�L�����~}�����	�g���N��+L���^nGu3#( �Y�^���d�:PC�M��=?����fny@��]�	P|���&@�7��@��Y�����6@��;�P&�y����=&��$���<�l�|�3��c�Pz�hx�<��N��!�;MS�\�Zh���	�k��V��$$���l�g��M��D�.Db��P.G%�e�9�z"M��������L��bo �xx[>8+�?o�@��������a�.(&���g�@`
Z�m��o-�>J�/T[��l���U�C�������H��y�>P�U��
���@E%6D?��&+hU��&('�u
����wQ�i-��o\�{U���U{"�H�����7qr���m�=e��(��=/�T�8�7y4������1{�y~x��I��Y*������e7�O��h'n�>�H����wE�W�;�A�:> >G��hU����v�d"y�n P�=�!�w�8v���s|}-�{����@�M6/S��R���W;!���m��e�C�K����A����5��H���N�C����6.��*� Of9^u��H�vLu��=�_��Z�QS�|�! ��Q86�
0}�}+n*������}�4��2I���?���Wj)��W��^���~��U����o���U?�G�S�>���rf����������f�x����?����������jT�����D+���0,�y����R���_W����`���~����������gu�����}=�ST�����,I1-�,��7��v����3�j��i(bHAef|��$�=���zUI� �0}Wy$��d��=��:�������rz,��s�=�?�@��<��q�K�"7uwK�!x�x
e�8/��
��_ �l
�)qZA�|�Qj(�Y������`�������y���o�#!D������o�C2��.�\����G
�A��������2����H���c�E4������lj����u.ZXo�Ik���n(Ow��0�����ssG;���+	c]��b?^�=�77�7l��n(�C[d��7��Q��P�uq�:�:�zu�^����K��������j6=x�P+�3��@HvN/\Nj��@��r8.tT(g'��a���u{�-���0((p�|�E�
����4�V/f��,��R��$��f������Z��Iw�� �^��u��\�9<;��i1s�H@N%<��u�V,h����Iz����EA�nV���u],bt�a=��N���w>��A9~O{��a� �~=
�Ug��-���H8���1�B�%�(Nlu-�Z������b�R��*�K�0h������B���������T�������g'���]:�����0�A!/�j����4��U@�R>w>�>%}��(�)4BI7#�����c���b(�:5���=�&�K���6�*���3�%|[��@}t93�q��>��(�Z�_������aW�����>L=�g��+�nE[=���.�QR_��d���,�w�Ez
��Lau����R�t)w�����,hNS.�����N��9��6���
�A?��^r���8�UR�vQ��v;_�������&/i�*
Z���m�7�l��Y	�<�-.	f�����E
�4�i,�d��
]@�>j�S��P��J���2�����G"����y|W����=�9��\k	]h����z'�FI����PF3"��������%���2��s���`z�qtv�K�r;�9���QoH0
Zdy��%��*.r���Wg4�F@D;��F���Y�C5���Me:b���k��:x����U�1�T��g�^��������')�as�!+%���'�u�{}\����#m�����f��I�u���&�J���`+��_J������j��6U7��m�S�=6�i)�/c�D�ly��}��H����-�����X�f���`Ah����7I��=�	����Ne����1�o`��YKb�5e��Wn�(�l��E���8.'J�7���nS�;M�]�NM���(�
%�b+�������3�@�%��Yp<�l*~�|K���:n��;�`���X�h�q�V;$c��J}Dk��	J�Yg�c�H�!h'�!��XM��}+���e �w���17������A}>x�1��������.�-lc�Uwu�K��$8
��!�!�i�	S�����LD�$�c���|��E]�0������]�>X���K�r�-����d��cf`hN��\
�b��uX��Ta���5��P���o��6K�M��r�8�!�-��$�[e_�b���%�����&e��Z{^��R�������ny�i�,�kP�_eC�i��]H�!��W?-���:r�f��n�B>��Ul����c�����B�����`.W�����.�qT�BS��\�yL=�5j�/$��8������W��������T�md
}Qd�@F�rg_
Rk����6a�jt��3Uy�C���m��������q6���oja��wd�(C�G������!_}�#?�J�������#Y��u�U�em	L�<y�����`��{����f�=AxtPy)K@��h�����c?7���v�j�k��:��a��~���WG�C�qVR������M*!���l��+�
'�g�R���� M����
��'��c���~����Y�Z������f9���9���1R�HP�3u�(HA��0�+p�i;}��A{!Y3D�-�����>�Q��v!������Q&9QyU����
�j�?Y0�1���br�z�#=����e+D9�9.���jg4��4*����'��7}K�����^	�BxfJWh`T���!=2'�������}cc�����{��=��Rb1n~��^������?�6�����$BN-$�}=Gwm��.2�R2�"c.%�9���C�%�~^����^�Q�<����N6{��]�,L�!-�b����?/9����!8���vx�������K]Nl���,W@�����1�l�h6!����F��|0@wj�1Z�%=� �r^@�k��S�C$��*n�K��Y?oM�A��c�z�!s�y�H�C�����-UhQ��W���_;�w�������
�~j�fl{�ca
���\%-�&�������C���������[F���0/[Q��H�#,���?,+/��]�\Q��*��6'Sx�w �0���v�z��Xk�F�c��F�d��>��z��8:�����7#���������Q^���y��$o��8�@����@L��LO��,@�R���1?�?���a�cNQg	@�n����@��
��N1��?g��3�8:�K�,�{a^o��g�2�������~�5�D��Kg�6��ai���|ruvKX���9'
���_
�%IZ��-0 ����������0�Z��j���oa���Q9o�ch��R�2�`�I�>�������Mu�0��5l/]��}`C�r������
���[$r�Q��G�^jC���(��_�SR�{ley$t��
,��d��o�g	N���@%�%��c���]���}7O_�����=y�|P�jM����� :Vx�!~V=?��T$�y�_��c?� ��L�������n�)��v�F�����L��iMs����^
�����U��4WN��e���9Z1x^�'����p��y������-�dH����%����]&���%�l����1�����!�Y�}����%�%��0Y-���)�?�F4�Q����.��9�Y����k�:��������>X��!E?��4�cl%2T�/��M(��<�K�`Tm��L+�.?�u��e���Sv�'��i�C;���#X25������K���"���$��i��p��u�y��8;n�5s��Z2������\���
0Z����/��Shp�
���9�?��J`� ��3�����w���d+b��^/A{����>�^��o�Y���b�R�be�Y�=�@�G����.��&X�)[���z�z-si�b��Y�f����lD�>���{XW�#��C�����~C&S���+���#V#���l��T�d'x��)���8�ns?���C:���!kF����d7�^O�;N�q-,�,oKB��S�?	$.���Gf3�}�������e\8�������!W��yZo# :�!�� ���D�`���hq���l�����N�c��!����J
�[�?�(T��6����������M#Z�FT�����3��C�6�t=��KgT����=z��{�=-E����
��8�;/�d��ww���"�=�P2���9�
j��E���9�6l�NB�*�G�o��x^���Br�m�����h=e��������6�1��l�'�#�	<c�"
(��u���F.v	�@��9a��D��#2gvs�����_�%e�����I0�/��x>����1�9 ��z��6.���E>��k���� �R�iF$��<�I�����*�f['�E��E��K�`������u�i����������w]"��R���Ah�'������b�����4J���J1�68��ag%�hf
�(_~�u��g���?�S)�h[W����X��T[�TgW��:{�!a���/�8��|�:���)kf��#jb-B%�7t��|l�4�P�W�7��S��_�V������*�J����rEg�!n
�"}f��|�'�PE�9=��C��������@�U�K1�v0Q��:u��z���C���5I>������D�`)[����w;������G>��+�k�PN���YT�\�:+P��lB�9��������2�8���fg�������L��%��^�x&��f�:��coy���VN!�������A��w,�HKle�XC� 
`��Ow�t�V�jj��B�%i�����:�������7�I��rf�;O�?O��Y�j!�O��!�i�\I�� �S^�z_l'���T�����s^�:�y��n��)�[���qJtL��F������n���x��\=���~��]n�;t�f���6*�E�d���b:w�����9���@�CG�:�8�d���N��[���8U �h&B'����=�Kw������.�v���s�k������g�ZyJ����}������E69�W����1a�� ��*H+2��=4��Y�I>�Ns&��4'k���u��f��:���(n2�-�JF�D=(~���`�
�.��g��(:uoA��+��L�,��!*�F��d����(��+>b:�u��&3!�$�����s�,g���J���d��C�\���ko
��:���:r�r�ID�j��*�e���s�K�Z�S��h�G�*\`�����u�P��W�Y���G�ZgQ7��	-9��,iE0��#��������S�bd*B�k����3���o��7���GJ���[9�i�'oJ�5�s�3X �61���;�+]�R�Vw,J�?-5��m������CQt��#8YI9���9P	��:P��pu�f��chm�� ����|�=�D��Z�#���Nl�2�-79��x'����ya m�������|
E���ZVw���7n��i��.sO�P�Y�����T{e�)�Q��L=���#���
�1u��]d��xw}l�h�}���
\�J�����~A��Ud��|����h-'�i��'�N9��*+���N\����L��'E�h:�g2)�i'>l�^%�	�vo&�^E��D�f2sK={�������h��_:����DsN��Q>����%�����:[d������(R������h��RA�%��L0�!Z{�i"9~������t�WnR�L9L�|������� �7�6<��nT�w��*p���8b��7b��]�x���#��P����qMH��x�rHc����')�q.LoE�;[S%�����HpK^��9�q�@j��J�
g6�����4���t��Rt��[t���	���������DEZ	�c������86f� }=��4�����3v=�\�����W�9��Z�^P��g��j�����d���<�6���NSR�&����#-v�5;�oC���U�n�yo@N�(.�^����*"�7�^��d[c����q�N��u$�"c�6�}E��������7�h�����OM���}�&���\����1A[������%K�Q�!��2x~_��7i���I����l��@��9��7�>�<2v���$�
�0���Yh{b�FO�[��"�51��XT����>A���<GN�N�8�H�P�\%(�R�,w�	I1�i�~yZ$����U��H3�g+S��(N�7�}���,+	���Eaa���h�n!M���q��Bd�	�A�
#�@/�R�s�b@kR���)�D��{�(~����w��
*FX[����7���M\������3�C_ws�"0�=����v`!�r1�6o������qX9�|�C�N�����P�c��ZgH��Gs����uA���6b1����T�(!`i��EKe��m��'�m��'@,
h���Bu{Q2�� ��\
L��+E��vNy��H�o�De�1�T!a����6's����F�)��:H��G�N��q���N��-9���`�_B������
U�$S_��&C��h:���w(�k�������,����f���1�dF���5}a� �'��:gs�Y���������{�I���h����0Ge}t�7���A�xl����Q��4��XJ���j��M�:�U&���i��g�=�Y�R�<F6�����@�e��g�����{��W�����e��b�(��,D0jW�x��4=��*\J�T+�������"i�X<g����E5^yd�z{wO�(�o�F�P�r���1�5=o_��b���PN"g�<g�����u����A�C�'i%T�q�fpjn�$\�ev�)i����`�
j��(��F�*��60����T�(��Kq.'�\xj�|���sF�;\�{��Y������&8X�NW6�``/6.�RT����8��f'0��L���|�
N	k��e��:/Y&����5$n�`����a>���-%�-�-��S�Q�P�W��8���M?GjwI�W�b��+���;�3,��o��e,ct�z(R3��]�����4�V��=� ���"��P;1���3i�c=�r/�X�u	F�����CL��AT�G���!o��������5����_�����(�H����W�l��ds��G$��z������S<�I"#bNJ4Qo����O�`�\����p�zB^�z35�Pq��Y�Z� `��?�m��oX� $s�Y�qT"�*����<�	�59����5%�)o��%m��	��0�zn�b��\�����.Ix����z(��BB|���?5g����Q����EJ0����(C������)�l���9y[a����q��p��,��`h����V����z9h���3��6���TGS��P��6\����,���}	3��[������ib���&�S(~�.�c����y�mc��+i/Z��$u�	/n�	
J��`+����&�>���&[���L�U'+h���H�1��=���P�@m0}8d���sr���
��b+!ZY�9��������*��
�����S����� ���5SX0�R9�]7�<���8�9I���o����!�6�Eo���.���j[!H�Mg�-L�#����&�Qs���Y�w}�3��g��O���������i����iC�F������������Wo���SG����8W��\�0~��=�4[%���>��-��T���D���\��������+���60mE^�g}Q� \���E��#�_�f�L�8�9gcm
�]'4��>��.�&I���Q�me��/�[���uI����)�
Fz���X5�^�Ug_�nl�1~�.
|$���|�A�c�)���7�>�rz[�\����D_�9��5O���h�a;L6�_h^�ry��$1E��RS��K��W�#o�<���2�mk��vQ���C(�8�9�l@�(*
���Pd]yG�P�k���P����js9��IR��iE�0m��
�:D^��{;�A�q?��Yt�JI�2�KQD����fS=:K�1��� �&ot�T�/���'�l!u�y��p�/X��m)��-'(P��M���Q�z�Y�?�@%�T��.����NKn8,��+�<���V���"�_��4�L��'�{ba��e�!}AV����^T���%C���rJ]��l�����fl�vC�6%s��N����B�|d����?j�"/�8�n�f��`2��$���pn�rn��$N'���.��,�;�sUO�g���1�c��o�����(r�1U_V�������y��AN��G
��n:P1����eI]����:��q�����B���13S�Y����Xk�1[=D�Tt�[Ky�:���#�oE��Lm�8Ot��:��������hK�L������	�@m��^��.WRJ�r�.�)0_�#����\�Ya�LH��;x�WVfxb���_��j�PAy�2"�m���k#��N[d��Y��q����M`f���^���H����X�U��x(���}�
e*�"Z�1��%��((�mnEY%�����Bmoj\n���^��'�����l���vFG_:�n�e�N?w�E����M�����l�.�N����\�!i��qo3mM��i�����M�8�q)���l3�](?��$���
���%s�(_
������u�t�����Y��{�
!�r�b������9$�;���D������}���R-e�aO���b��!����=D`6�&���\�$m�n�d����o/�&B�+��.�	����^7-h���^o#2��C������O�0;�H��#����*!��s�$�c}�xeO, �R�������72P�`��j]���y7���c�=X���6�L�f�fpL!��d^�5�����6�oc�q�����,��{q�\��p�����0�W��	kC�1'R�pj�Y�$�$�������,�<��ZA5f$&n��yx@/�R�����/@
��#����^�K�yb[��eF�s/����i�w����MF�dCY8������7��I��s}E�Fw�Qn�n��Sgf���Y]y+�Nu�`@�H��i$��/���"J37�n"���&���z�T�"��#I�
�����A~�$o�YC��{��5<G:!6�(f)�{E�	�55b�����2Y�zL`��+���V�&���a/R*Y�!�Ys�oo7�'�7qg�Amo��Byf]S��D
���3�0�����5���0Ar;���d_5[�>���w�HiIo�M@�����SpT���Y�WLKoZ*�3\���
'�lPs�z!nh)[gd@1zY6�#�`P�MW$'3t�\,/���4a�
�+�`2�(���$C!�yVbE��P����O��S��k������I��D��I�l�E�W��"_��lm^8�#S=U#L#����3t���f L(�����������J�����b��c�QO(�] ���C]X������s�����l�$}i��d*J�<%���e�����4�����P;)jo�B#Q��U
B�q#L���$'���=9o2���n^e�8U�:�X�~wy?���b_\�~#�+�D{>�v����4j��D���,�����r���VJ�T�:���L*�/$���P���W9�A�Pj���c�I�\QX@r��d
���?�}?���?�^!���X� �D:2X�:���4[�����L�p����R���f���	[��(������%(O���.������R�| O�q:�U�<���\����eIr�Y��6�9rrA�Ko�U��v���]$ra�k��r���j� "�R�6�'I��/�����[�2qh�l�2�(��+�����Md�<>�\�"��K���[HYwE_t�;�g��j��������{o��A��N|������������ZA0]�����N&���(�,��.���F��;k(��O"Dh������[a#�
"PQ�f���	z�����������������Z�|�]�uL5�A�+;��f�-#q�k�\�������wx����CG�&EG7u!���:��e���&��Ggp���,v�a�K"�h����I[~"��(��`��u�tP1\�j�RV����'�U���qS^�I����Pm���oK�!PJ�P�m��vuS�IV���q���n�Y��N��\�I"���Mf��������K���#�8�T�KyY��lb��Y��{����r!�&�p3�LQ;O�
�4Z�.�q����:s�`p$;��1�)!�'p�+��5�q�-h���b�y��}�q�S�03B��'��� ����t�����E<e��9�N[���\�T�xZ���GG�n3*��h�/����D�x�����~��aQI���N��3C�
�#�.=�g1��@����x���" MhhPi�>*F;���Y��PA��T*��)�>J/��3p�������#�1�W:�����@���~��Q_*�g�H.,�M��7�:E��l>QPB�6D���I�!���������3��Y&����^��^�s��G��5����L-B�t���E'
^�������K��a5�����	�A�b���
�B�h|f��3Zd������s���Q��*zh�P0�����?v�(.Z�������H��(��K?����F2@���}>Y��������R!���%/�F���yT�p�,PQ����p>P^���k������x��9j�v'U?�X�����[�6x�CHv"(-jn`r��C�����"0��?��,
�KP�N�m�9���?�r]7d�R �� pF���Q���l��H��J�N����PH��v9*��W��O.�^����U��)��HPB%�I����*�EJSA�XBQ�s���Qk�U�J��`cJH�L�*�0o��8u�S���%����g�$T$��������.�DRo�:�����S,�L5�T�4��c^��((.�>o'����d��%�1J��`(c���oL�a����a��S�B�T�"#]��VP�:5piO�56t����b]�w��H������>~�7�GG!�P�Q��/����H.��%�{��k\ �Ra2$owx�����*[�������SY*3�Fj�|�\��.�.I����SX����YC/��x��l������4G��pi�tovY �
�eB1��T�r��-����E���6bb@��+�;�r��[�JS�~#C����)1�M��C
�t�
�����FZ=�`�����lK�:�O���p,��X^Q*��+���[��Uo8K�����\�ET�h-���M{c��G��yP�
�����}o*�oXq���iuRq��	ck�����D���ml���u�Hw����n���S�*��q�����f��(��0@��C|�T������������������KK�j������T�� 
����FF���q�<>:U���(���CT��� W�����3`N�}����o� w��5�<��+��(��8��C$�,�H,��JQC���(e�&��7biEm����B��bY���`��{�M�n�#���N��B:���a]A����h�j�c��t, fN������$ {'C�@'O����������i�W�Y|����+�*�$p�W�Jl�|�N�7G���������� c's�`�D�rF����VZ5/i�9�Z�������|e{��,w�8a����p4<`�w���k��,����"Y�L����1�8P���D%M��F"+�gT,��K��8c��m�e�_����E{(�3"�UO�$#�h�xZ�de��[N��P�6k�:�$�l!�����0�/�K����g������CE346;�o�a���|%�YN�j�"<J���,�s:�_����� � OF�6�<�y��,�gW!�me���0��W6��+����$�=�>�5�F
'�P�"��������M��7�7�vL:���.%���Eg`r���� ��uOD����������b���ip@�b.!��l���#��n@3�HP�Y�� �ZK��~)S3=@Dj��H��A�&7}��I�x3!|��&�w D"�P��x���&,s��I��7&���F��v�z�xB*��Gkl�������A��ANQ�V'������t�u��T��yf��S�k����ut^��Xy���t�"�p��n�:�pq��m�MB����J@
�n�(�(i���F�MSE4��)���A��PV?6�PW����t9��=i&�4��4��R��q1��;��v�L�������j��(�8�+��7��$x���WHU�i>�qSx���0�K�
�Uu@����O2k��X�jJD@L�
U�v���R��;g:��v
�C#�b|���"���Y'Ou7���i?\���\z���:W��9#D���
%��3��6�^��i�(_��S�8�1��t�`�!�|���V��������<������z����)������.�����x�q^v1��Q"��HW�}E3�&��/
"��
t4�--q9=[�/vj���
����Ki�%p�\��8:�-3��LV��9�Jqd��#���33)r�O=+�[��QdT����w��p+U�3O;�;M�/�nU���d�^�wE�C+�0T�3�� ��P�
g��6�:�5{6���1�I��VFC)G�
�Bb���������h�Am���;����w#�w�1?�������I�P8s�b/��n�6�G�f������{���(F^���K|��ju`G���3�p0���y���V�h���a�i���`�����o��|:J�c��Fp��:��[��U#\bg	,������(���	���ak,����������kjp=�}J�=s��le��;1�R�L��V�dC���C�
�y&����-B��^QJX
6�����e��'���T|R8����p��&��C�"]/�6�PG���$e��$w�����@��T��'=����n����v��u��	9�[��A]�d.�*R�kBh�
������D��P�s0��o�5�b(���a���l*�Q�#�R,��Y�c�T��'��Z��>I��%��wAq��*v�c��[�#!$wZ��:��P6���"��1�� ��~�r*��4q<r#���'�5������<X�%��!���	4�5#����:��W���x���7�����KP��]\��ha�[R�hW����s�jOLg�SM�:D�5e�:� Xj��d�0`��A��}�	k\��������Z�&0�N�[q�`��������$���CF�X�s�����`DV����?O�nJlc5����2���.��f��;h:7�*@]�y�����s�W�p�����"c}X�E�GidX]���H"���< |�(�)�jZ��6��[�S�)*H�l;h���Otlx.��!����w"�����`��^a��^���������� � .l����L�!5����R�T���� �jO�W*w?��R�"��D��5}��>NMo�B)A4
��E��<�G���m�<���9E�d@�W�3�7�K��.�������a�dk�B0"���w
%��8B��X��#���*2b�ZBe���T���Q�J���WI]C�� ������Z��P{��� ����"�����2$=�F��<|T.,�bC������e��������Q���JF����[�A��B������l(*&�i�C��3c�DWg#�x�"� ��-D0@��O!���Y����K����|�:�Rvd�^?l��r4)3��D�s
��1$�����	�L=����#��n��;���4h{q�tE������d$Yj#�h���T�C����$�w}��R��S$�����J&�5����������(�$���?M��!��a����w94��@��WD�S�EE9%����R?�o�g�"BW��[�SV�y��`m��
��)-��8�q l���a]�]b��)Rb�t�yhN�z:�)���A2�b�0�"^*�W��b��S���jK��(�4O��_�uu���J���E�z��#��H��]��S�:�����lWy9�l�#R����v9H�['(g�:��J��-��^���k���RD�t������8*�g��x�s*
����<����A�^�q<yr*���E��v����?=�Qg�T�\��C"��V����@XQ ����	���yv
�fRY����_Q��p����������_~������ME�������$:D�b,#FGx>Z����:�{�`�>�b�ZJ�8n��i���=�`���T$�,.�t�X�T��d|���j���8P�m���������#�TV�h�p��( �!{��������6�������du���WT���S�����T0��@xZx_��C2����
�������Q��l���7�	���j���=w(%h`��0��o�A�Y�v�d$N�;�)�W��>ED�qY�I~��r���Z�Q���/���v?���#���H����\8X�dM��9s�&��iJ�_C����.�au}�?�0!�7��f�t��=�pf��PY;�.�K"��Dh���,kt&���.����M�R��HT ,z��O=��a]��E���Us�6�L�����U���R��jT��8;�?i�f�z*Zjs��J
�������������,�K�RQ�
^T$�d=����Zi^�T��T6�)X*�n���(���:�hmac*��d�v��?�)������`�!Q�@
�v�����nz����k��� ~mFh�J�o��M�p����}F�D���UN���-OAx�PG��C�
"��I�R4^��'����%��h���SC]#%B��%Q���`�9d�LI
*P?t����9���M���n���64�F��D&�w�D���q�>���c�� CP�0���0j���3q
*� 	�@��s'ruo^��e���o)�:���D8��O�^ZV���^r�u�\�[�C��
�BS�Ol?��#��r^T�px�Dro�t_�j8���~�O����^�����|jv�����/�j���������
����U]]������������w��~���� ������O����!����_��������M���Ka}�~}:����?���� 7��o��QB;��~��|��	���oW��Z��Pv_���r��n�����=��A�p��+E��W���9�����1�!�qB��
dz�X�v�������Q�����R��'�1�����/F�x���m9.Ww�����������A%jK���Y���PSq���{���0<��P�5~��h<�?�Y�5�Z�����f���_�������cW���YU��9��>���������t-���-<N�����^����k������R��*c�y��O��]�;T%�������D3B���o������M��������/�^tE�t��O�D��C�����6,�o������}��~�����Y��}�Z�?<��}Z��o��k���f}ss���n����Fp*����K�{~N��n�����������O�~i��h[����C���3�->�~d�@�����"������o~��7M]�jP���
��/��l�����p(o�o������^x�X����N�@t���j���i)7ssr-�>���\��z���U�y���a����b��vs����a��QV����1��(�k��B5V�(T���,���>�n�����,7i��[���2e�)���(�V^��������\s�C�O����S�����G��<�Q���oD�������]4J�<�]�#��[
Q����n$9���K�����F��HE����	�Kvh������(U���z�z�4��a�\%5�/�Y;~���3su����k��F`mz��/�Hu8-����j�B�k�m)��]������r������,���������o Y���.O�����-5���6�|^Y�����:{������s���F�U���a���j����o�)���u${���c��i�[�i���n��s-��Qww�G�4�������C��	������=��e���V�y����k�r�?nY��:�B&�i�_[�������L��9W/g9
��5f������o0�r��K�vR�5/�����W�Y��7� ����;�oE_?]�����\�x�(�\�&�	��C��������.���'������9p%����+HVA�vy�,��_.�/�s�@/�0��7u'����@�aR!N{*��*P]Y�����~�<�_���%���<����W�c���oE�������`K�N��>Q(���|Y���.B�D@��Z�e���&�&?���T|�%��e]��~�j{��P��_�C�5]]�m�/����R�?5<*�Sd6x��������g���E<��_������O�n��z�"/)`M�X���������U~>���:��0��)�v�@&hn����_�����8���3A�P�������L�g���w1N�[���5f|.�Nx`�W8���PB�S'\ZVWjL�#�T��+���.��x��l��crjn������krmj�����G�j<��@�d6=w�����������;�;
%��~K����I7V3��<�S����!L����V�~�����w����N�����+s�9C!�.�-zZ���������m_C�M���5]���$�`�VI^V���`����������U9��c�X����t�����`������
����Q�%']��<��+�Cr���`fE
��9���V8��*�=���w�I�2���YB���c!o�$��~L��l��:+DB��:E�`�G^�W��-k�+g��g+��pH��tF(��r�7�?��U��K���?8���T��.�~O�+�k�#� �w|�������Yz�������r��y����dF.O(�s$�t��I	uD�h�����Z�N���3��"�{�Y�C�9[<GU8���i�t�0�l*y[��i
�K���1�Ek�i���)�R�#�G��NH���U�8o(
qa2�Kb�{� �%���Vv������7�S�_�w� �q���b��7/>Lvzx)�7�'X��9Q�B�k&����I��^��
��p	���rsP(�g!
���6O^�n���YPL��.�N�����*w�a��~�[��yUk�x�E��P����x9b�N�8j�iW�'yq������=���"����mSxk����B���0��M�_P��"��3cI�o���<��)B��&�b�h���-�Q.���hm��S���]%L�������h�N^@p������(�����r�^�g�d���_�����y�|-�����y{���2���&������Y�����_�
!x����`z���b��E�~������r3�:R+9���?]~<)��T�v\}[��M����y!���8�<h<=b����&w6.��{���-�4�4�IBq!�]���#��6�S���|�*��$m��_X���O�
�6�U"�7)BYX
]��uJ����������2V��&��E��	�Nl�/�i=�q�u\Gd�����+&*f�
*��j�l��8*T6/���4�p��BK���s����E@_������J�]~)��
�r��CE�1����LR��w�nS���7��aYY��=f��%x�=����{���'��x��
s�=����Vj��!�UmuH�B��8�����gL�A�����N|���$b�/�`c6(n$^A<���	R|�;#p�\��u�����m���HB0Y�����������X9��B}�?��>s\��4�S���lr��`���j��tGue�S����.i��o�>vYo����������������"w�6������<���<��z��Q�N������i��k��������4{ov}d0L=��ob	0�'��T���Nj(L�{/g��Pp���Mo����u����x�>��BK�Icv&������n���H.���0�^|��!C�9=�N-��	[�;�
��bW�����Bm�\������b�������vL����tp����#���q��x�l��<���Q�{���r���S)��*YQy�� G������h��
a�F�K\mG�^���o�m�����l�B�P��'�i�f�-Q��h�)�;�� ��1[:�����+����a��^������t��m�bC�:��_d���U�2��]ZcL�P�I&����C����\����PZ`!��\3�{fwx���uG��(�w����!0�]�~����Ze
�Nr�����!����gII�,�(Da���p����(��BW�o����;�^��x���W��k���;�����u�Qn�9:^����(qd����W�Z��z�kBw�c�}�Z�6��zt�	{�V>������u2`��$�j���*K���/�d�F�/��"����/	G�R`ju��U���F���>xhu���vwU�����X�vS� �2����O��R�q��	���y{)������oOs$��~T�����m|6	z
����VdL��~��zEj�>��7�r~��L��N �_(�	N�@�X�Tjr.�i����]9���9��!�4���5�� >CN���r�@�3*���E�;}���ZZl3f��8G���4h���c�Pc���E{-�{���������R[?A�
��l3������'�X�F��{b��)��O��q�����(|�-�rH#6v	��V�<�_�����U)�z��6^\	tr�8-�F����zZ�0�������'�P���E�-�A��&����7oI>�����t���������
���%TL6����o����*
�`\�\"��\j��w$��,���k$i)��"I,p%��;)�%�#������	_�l4){76��OR��� O%����9vT�D�|���C�N��'���'��k�t�v[���u,���r+(�����t_�/+�C��b
����$����*����5u�w���&=�ZS��b�p�$����r�O�"��,��H�16n��}1Yz/����������c]���a \i�1_J�:�w�3��u��.\�h@M�~��\�1���n�r'�^ ������3�<����N��t�KW��o-��{5�^JG��}��u�]Yi�_���,I�����bE<���Cl��_���csej#�z�c��s69#g��E�1gx��\�O���T�+�CSg��2�-���tc���u���FE�=L�l��{T�nL}���t���;W6���\R��H�n��P_���Ht�Q[_*��>�[�K�������KQYQLJ���@�>���c�\���S�%�@��q��I`#��u����V�+�z�-x�����-�S����s&�#�������n6���*17���&�mfI��������F����ZL$qW�1�v-�Js=���Z}]u�u(��H�B���y�cl-��7��8���.����h	�L�$��������.9f,������b��.��}�S9�����Y����z��T�����5M���^���J�`p&	u�R�Y�/t��eC�Lq^T�$`D����9`�2�c"�t*a���b��(ZY�-�������E�<2���W����j_���j��� �\d:�[
q�����r���<3^D�Hk�b�u_VG9�
����;'g�y�?�b���Tb\K�>S��F��N�TL�VJ�R���L/��U�I2�3WP�=���N�\�y>,�B��te!n�������rY�SA]	�J�<���ry�-?�j��M��+�4
#�
�C�
���[��7O�Dy^'�/�.�����9]��l�k�+�h�	��_,���:�mL�G���F��a�����$�?I.����d���l���K�
���#$�P�
����"ek)���o�r?�/�,����@�c��]���Nj�-I
�1;h�T�FXo�+��,8`�9��2'����iSx}�\��]������#�W��I��v$"�FN��$��%���Wy$�R��r 2�Jp��M����?/���H���7��"�S-A�}i����
���-f+���cez6C�~')q�J���o��Q��a��������\'�{��_�(N����Og�,SO79|��}�m3:��@!�S���v��:����(�E'q9+:(��Fts�|E[��n�
��<�c�������!���x����)'��8�S)��C�����lPWK��T�|*��^B%#k�,YqlJmA��=�/#��'��5Z�������leo�H�
��c�DmE��0��7��#�7�iql��"9��I������m���a�wSWe���>Oc����A��xk������o����f�����Q"���B�M�A���d`2����qf4&��W�e�R�-��U{�ZGT�aphA�t�����sx��	��VW6�8Z�@������>�?��Y�V���?���pu�e���Zg�s�dw��q�g��n�����<��-a�rp~b�V�(�>���������9���<�	V�QD^y�� ��+fP����B:��qt t���y��!5A�F��m&<�K�=F*3?�|��|Y�����F)�6(����������Zc&i%�[��6��T��x;uY�{'r�������d�i�C����S�1`	5,$��:e�:T�R�c_�/� �^��	�;Vy�b�_'U�&=��,�+�u���>s#� }���p��i�mb��e����Oi��a9@���6��I3q�����@�%��3��0Mh��\�Q\����F�)��@aa�lE���F�p�F�:��=W���3&=����W��F�H�w90�.���.�:I��"V�}��D��1�;�CaM�N����H�/b!b%TM�A��D����c6(o�k��CoC�4�����,�|��������x�$��.��A�y���(���]VPJ}kT������r�t$�wO~��&��u}�{	���EA�_&����L�Kr7����$���if$��km������r��$ty�W�Nq���3��<��v��
��Z��#>�<��A�s5}_F�;��|y�g�t��1������p�6�'M�(Q7����A�bN�8�rkm����}���c���X��q��bG�+_��u�p�*\Law����k�ED�H��5� ���KR��������3�c�f�0�m�8�:�Z������J��U�>[LZ
�2��O'�J���t���+���� 7�c^�#3��VcW�E�x1�����|�Q0�����V����xqlF�h*UK�A]QR�
�zqRTD���%Om������fB�����!/.W�����m"��C����UR0��aI�u��>��r�f�lt��xs����Y4�w�����M������M6��	���BD���c����*X"4��$�lg'��s���v������p[���m���t$=���:LL����^��%����9��(�4���d]�qN����u�[!51�.
��>�&�Ly1iK�E��<�Ea��_�-���E�H�����E5�`��
m���&������X��9�y0RH�6��xYu��|�:�&k�U,F���6w���[�j��w�8�V�B�S�����ed".��N�a.*9���2��������zr�-<��F
��K�\k5��"r�^V����f�$^���F1��K.��`Q���Yc�����V����N{w7�?6o� �-A>���Co�������yr�E��/��^��2y����.'��'��+����+n�(1��O;����8Wz�H�Q�P(^�IS{����k�*7�^}X���&R�U�.�E��"2�c_3m!���-E��	�U���������1��d(?�C��{����I�h�������a|*��9M��"���G$�.����}kW�A�^yM�/�@�-Vu��h�<`c'0<��*�l������>����.;JOBl���k���b��
��3���E����iUUb���H�:�����v	�r$u���+�_��rmN�v���u3(!��b�I^��Ss�{��K�s�?BGJ���R% ��@�%BOV-����b��(]�GH��$7��f�<��)O���`�i�49�I��|_k�6�/yc�������E*�y�b��SX��yn|�k���ke������4o
uZ�������������;?;�j�WI#-������V���H�n7�T!�(��F.dE���)f��_��� ��E9�&D��)n�n���9������ ����<�����G�V�0�q� yz����0������������a�<i��*[6�r>8�V�}���<v��D�i�2.�@e-�����%�L���%�V���f*�:3������)D�����$��?�����p������,��y�|B��1^TOB��T�o�M��e����4y�{��r��`d�YeK;6V�7��/��d0ka�����x�&$KD�U�R����n���E�Ka�z<V�_,�F�w�~����u�f��
�S�,���^��i�xO&�MP�z��E�!5Hh��r���%3u���1n8Wk2��Y'�h�M+��.�
=&��R��y��ZpzJDP/K/���X�H� �g��7�n��~���Fx;���hW��V�eSb:7�)�i������6:sXM������-vU��0�S�����h��Q���Zg8�c��%	t���n���Ic���:������p�f�<U ���5�3�s�U���c:�s�j/�zag����
�����=��o�3��|�F������H������O`S���!Q�dk���M�h.���'�m-�����\3{�s���*��>r:��^Z1�~�:�sq!.��.������@����;j<<�y�_����
7]V�h�2m�Qh�(�tXW�<H���bx�:)U�0�>������l����1�P�k[C����@S:����x������cs��(p7DX�!=>&�%�8���s���������PXT<4o�����7�����������g��j�)]��f�.�;����8tg��v���u�HF��fS�9��H�^2����:�,�uy�j&���N,������d�p2�V��TMl����e<���	�2�\��t���&1��������������&��
�']{�:4FBn������K�:������}��!�'g�]!�����D�4`�}�C�aj��������[%�����<��=v��;���_u����s���!}y[JD����hv:�VZ�������������������\e��67R��6���7mQ!
Z�fyq����Gc�����%E
��������br�8c^T%h	h�_�v�@����d:��q�I��f�~<���E��<j��>��[��1�����=`��DmR;S��a,+�.��Wi�l�*-�~^�Err�J�G	���]�v]�n�6�1�H�}���4�Y,��|���+���h�q�uJD�s"C������N��MH����'��R99��	�.'�}���#HLHY�����j7�eOB�	M��V���aHl�[���
���(SU�m_�����wwJS��D_=V|�).:�Q�����.���+R�1�'D��|�49y��6y�d�/O[{v���CDy�X�����$"w��Nn��-�b�nm��4�AQQ�v��2���<��^�{�I���G��R���e(TE��\|F�Z�����e(6�~�n�J
����LF�<u�A8y�.����L	EFp�D���e�����
�����SR����� �e�H�!���*�q���T)��
�)f�< D�P����i����'�ED�B�.q��Syq7��K�_�����x�k'���z��{��o��86u���pB��+�J���������K���
G��'�~��YL����e���H�G���!�I����2���GS[�S�^��e�l���(�3����C�z�Q(g?��JanG0���Q�m��N���!:��6�}��V1����r�@��3�}2�����Vl��:���*N�j����^t'
	�~JG��*&e(\��P�j��j�9=�0��e��U�R	�%Kk����z�?���<.H����2:��
�p������e�X�Gg��(O��K�f:�I:4�R��l���e����9(r��1`�������-gCkVew���
&��Zj�Dp<FI����:$��oD=6��N9v��R������Z��������*jq����S�UO������:w�$?k�^�a^��ByaK��m=��KC�vU�mu��EdP���c��Y��3'N�������9'�!�jW��k9�eF�����'�@Col�]9����+��\v��� ~Ud������j.m:�w�p�`�$b�yt��c��&��S��9�U��Cq�����:�\����l6���6+�g�!Y�NZ���F�����c��{�]�3;%Jw
��!8F��^NFh��e�%�
s!Jh^?��I����pIG@�nc�����^8`�8"#d�s�@��dG��\�����`x���
��X$M����(ld4���q�����U�����V��U�wMs�;�Pi�;�
�^9M�G!���&�8O��UF�X�hNX��h�ci^ (%��9�D	�P6���b(,}�Y
��{��������F�/U���P4=Rd�z��0�U��dA7��6�DK>�1i$5���g`DA�)���`ga���1�u2������	�����4U�@�b��1�������jn�r��d�9��v:����+������S� ��J��%K�L��V09�n�Q8nc������c{ $u��e��
tU�2����HQB7��i��N��#�uZ�%D$�m:\Z�3�t�	����>���KU!=�i���)�3�6�p��_���dI:h���������:I�rM����
�G���YO�{V��$���FH }���������Y7�P?��'���"�T]��M�V���S���y/�3-U��5����{S�H�'y��������(�b��Cg��o&�^����0�|9'�z��T8�@b�����>��p�B+B���B���|�y�<��T���"�z��sCS���4��;���yu�CZ�]q�������f�R"�@gk�H��)S�:D����7�xH�K������l����K�3�~Z��	$L�?��M����tq���'�A=�{NHG����� �wk>p0^k��F8=��M�]f�H�:=��S+���������"Z�-��]���y�Z�6O��=�����L?#�a�Yo�����:�[(7
�,��:M'�<�q6��\��PV�����t_�y^���gP�T:H��C�+�jVt�e X��t�z<n��D�V�����j�~z�.����<KK�'E���G��U7���D�d�)e��/M)e��-;��a;B�k
b�����*�_#��b*EKI�,���_,B�t�?y��*�Y338:x���d��m�r������E��:!L������r��BR�fl
�9���e�n������\����X2��7��y��;0u�TFYoQ\��o�s�(.$�����7�BZ���������6���=�6��vG�W���:�(��;t��P�"����(d��q!FUu;�H5��!���&
���p�;I3�� K�*�Rlb`7qX&/�V]Q�(��~,�c��G
��(�&���d
��j��X�K"��H5CK0�,����U�e���p��.A%���e`��T�M�s@�X"�@7��c�����c��6����,�'��C�P��v^
5	��s����-�Tv���n���a�%�A�q�������������n��u0��n0��*�3��FY2�����#�
q�@��������`D�=B�1�2DFg��m��+�
g{) c1��a0Ac�0k7I.Jt4��H����!�H�<i9�a��v�M�|}
���x�Nj����GO7�����D���u�Z�����U�$)�� �&;�0�G��Gf�0�.?ZE�F��f(��@�p	��$h��_]'R�f��d3x��b�U�$I��yS�BKa���(��!y1�Q�!�@��(�6�XZ���,YB�)n�[��]L9������#���K\���^����208��Uq:m!�!��4�cvV w��9��ef�v
To���(RM�������m+��-��/�u�j������!e���D��,��>B1�M����1�a��F�����<@{���&F���L��ty�}`�����,��@�D�["�0�N��(c=U�$)Dj����T�mc�G���gJd�-	�L@�_���x���$�*�U&=�gK�eu�c�X��������%Y9�R���4/�AZ��$XJ���5o���������K�!�M�"2
��ig�2���$�yiC�����}e8����(?�X91M�������������U*�U�� ���f���vL���:(��$5�r���'I.@���������\1=u�Wio�����w$�u(�"	.�pK��jB�f���(��������t��
"��5�o��[��W|[��@�����4Q�H.�f�A��O��h���E������/i]����N��H���)�����r���	����CT)��u9|����M����f��EPoV5�/�d��2�&���%��E]���B��
�o�����6��W5�Y��).���:���������>`���`;�9B��>��V=��#�i�=
�l�\��&$e�4�T]�Leb�.������`��
>�,R�(�*�1l8%������`gr�v���2{�Q���@����Z @G�����YEFS,g�v�t���l���O\Rwc�
������pW��Q������~�UF�1O>�Q����P����	m��`����S�nj�����f�m`����P\7������$X���Wu�E�t�����)���,����@�����fO������Tf2�t�K�v��:�P��n
�y��1yP���iPgr
 He.g�3<'+��r��P�p*P>��!��R��l��ono��<<�6�@�7������z���d`w��0P����w����	(�Y�����]��U����<
2`�yU��\�B8�t�P5IG�5o:A��P��{:�'��	������h��@^�Y���X���VB��� B��W�Z�s�,��������]A�����R���:n��y�>(�]?=�]��tg��6�������������ql�t�cm�~������
R�	�������qs�Z([on��v�n�t�^�>���6}Z���n�W+��a��J�W�m�Y����m��@�ox"��3JhA��--�^�.W��b ���Na�V����X| �����k���!*G�#��%&\([jr���D���7ZKK8&3
!c��Fo�1��>k�},�������j3���tu�f&������kA�y6���X9?��
�5���:[��sb�|���4{�<�����<�iHG"8't0WcW����; 0���~��2���ar��>ZH��'o�2-o�R���_���� 'r"&g����8n	9:Hh�3�5=��D�'\A�ZJ5�,m��&8�<����~z�$�(!�N:��i�9�X���������#�A�qb��1Os<�3t���:6C�'�����?�-��B����z};�4���=�I��hk���w�H���A�Y���V�^�W��{s"��52��%c�Z
q4��a�g<����6�=:�5�O����a�6��--���xk��0�K���W��5�M���[O��v{s��6�]�8��=��GJ6��+���`���M��'gQ���yL9:J@I��3���Cu+�N����:e��2�'u��P[v���a2�|n|������x��������!�lfAq	Pv�����j�|�L�<����~}�.�{\/����/���h'm��k�#��L��_���n�3Zr�yHp���Kthi�������L�^:
��!�y�Z0�7x�U �lC�UNv�[]�h�0:Rn���V5~n��}�� ����#Xy�UW��k`{3&=�:��:nxa�WC��6�SB�t
A�A������\v>��%��O� $p�N(I��dT��r�f5W4�S�oI1�������H�g��?����?$��?o�8V.ru�%.�
ffy���B@��"@��Y�9�,7���(L�-���
��?�S���@.��{�0�3�3�qT��/F`�C���Jz�%j1��~M�����\j
��M0A���}^���"�����Y
�~�]6�|��o�BK���Yoo�[m�����y�r��@O�<��x5���\Gg��z�b��E�@Y����q��t
�>[f���<]d)�m��S���Pz������Lv�=,����2@��n������
�x�EU�@����hw�]h��g���UeQX�$[����=U��ps���g'@�]������d/�����y����w�tX����b91�����q=3���D+e����I�v�k�kb�EJ���H,�!��2�_)��IQ�N�X�� �*�&oq��(c_tjJ�\Tm2���M�:�;z�io[�Fl�5���y�s:�Fo�k�~1Fx�oc�e�l':����98PD�4��N�Ex�9��������wc=
/��Z@����rp<-
�}�1�;�5���a�l�p �'��J�}?H�K]��ik�>�:��-�����bXV���x%b�lR���h?]����(��*.�����ffh^GP�0������z)�2_��K=�B�.
�c�������P��d�����!{:y�\��(���b&ay>�vv��s��c����dh��b��:��*��,3+���9�c��\�@:��B��x���4�y��eI%�B�T�ix3�5��t��Y�OG������n�
|��������� *%�=�e���Q���x8���������p7�C/��5_3���,���VE.2���5}��x)�t��PR����$�W^����S�6}�&��������g*]�A"4� ������"+��*g|'�*�������i��O���|L�P�z����n�i:�C�������js��[({�i�	���;.T����$��v���N8=O�%��C}6/�+K��mE��cY���1!/� ���0���<�Q�v��7����g���Y���Y�
�������i��?na9(������r���	coT�����
g���<gSt&�!��B��9p,�XHP�yY�umt/�K]�H�2�:��om�����J1�fZZ�iV�I+A�{�5�e�(��f�0�S#/*��MU�r4�����>O������'��M��aJ�0���y<��X�I
xO#JJ��c���;�5� �"D9��1}����8K����/U���P{1���
���ga���F�C�Z���]�c'>}�#���6��SR�K"�V��5�k�I��K�>�o��j�zU���@0(WG�'��!�*�l�h�������{�O�
�r0�EF�3:�0�5�p|S�E->�B�����lb���-�Mk�b?���p@���!�S����JN��c/]��$��$}Z��-<�e�u��n�k�����C�Ea�b���K���ca�
k���:0����CTl�#X�v�����+�@�:�"��>����q�(����	_ 
����c�����i�Y7OZ1��}����xq�fsj�*Sq��3������5m���1�(D7�Aa"�����H�����<N����#�>��{e�W��9��1���qQPB�<AQB��)+��E��=�*������7����ZQ!�bWt��A�#�b�j����zo���$h��[k['d���H���c�,�H������N����o��
-���&
A����@e����z*����;T��a�QA����*>������l��e`����0�� ��c`8�:�2R\Y*�2��E�?�h����wWi)����p0���N��j-*:�T_0���b����
x�6ay��V�P/E��`�$vs�������v.���A�"����CBi�B��W��)G=w&� C�{2t�F�����
M���Y����uR��)e�+p@��-u���H���9�#��s�x�O�oZImCL/�y!�����5��N_�%�2G�l�z�
���'%���jZ7��kW��6f���*9����O�h��S�L�"O,w���R�p�o�\�����`r �����M��s>2�Q(x�R ����[����:�5}.�A��4�3�4�W���1��Mz�'����f��;<(# ���]�j�"�C���C��7�RO��/t]�?e���1n.y�������7��du�|�����L�8��1��g�U�
���L��]��=����w������m����;�K8h��N������G�����L#A����$#y}z2���0n���B,��B�0���c����L���2��{}�ei����Sh\"2�*�����-� ��2���c���Xk��cZ������t��3���u�cyh�JcN����H�"�9L��n�
�B% �);�������0�[Q����?�h� 
�6vO�D�<�4���7�����m�h^F�``7�no�30��R\���cOQP�_.@L?��^sJ )��%#�Yy:<����3�)��_=��4�����d�)���k���V����������nh_�EWf��}.�
4B��i E�%���X��1�:�z��i*[���1�:(�����r��7�S��D��t[����P�HK���V����o"�.���j��&�Ra:�\�q�+h�4�h����qO�f�/���.�QFZ�P�,��1��$S�T/��rBz9B���+KA�y9&������N�A��1��J�H�����9���I)��3�D�5GF�P��2$9k��!wL�o.� ([�^O7���z~�����zBs���I:�w10��,�}^���c�2/����
kZ�������=�����z�E����GX@3�r����!.]�e���pH��D��-kfTN\j]�&ox��X��8/;[��0�S�{���;g���� �3+�d�
p�"��R�H����>�>v8ze�=5z_	���x\+�P�Q^�o?KD�c-�f�w�1Y�bm�`����a������l�}t,��������}���I��C�g5X�Y��f:����}������X���@�*dXD�=��4QV�0��&Xr1!�;����E&V�::��5�A����!����s��#Mtg�*�
�k���`
vEz�"d�yGF�����l^_�{��'��t�I�%bt�Z�j��c�Q��4�p�,D���TxY��9x�<�@�(��j���K���	���m�����<�����6�&�H-�-������xh�v�&�KepQz���l�P`u�:r�ya�9�R��o���B�:���aU�����AL�������������<#'$<�X�j3�}�6e���?@�������K�X��d"���9}8�s����o���l����q�"�]h{��n��>��U�X_������T��8��+����>;�C���F�C�k�������a^������I�M^
�a��n���v�g��-�ks�/M�.< ��y�F���T���h&M��
�Q����+���r�Xu�q"�p�����~z!	NH3�����+�������OlM~����NI�$�G`��?�/��yF���Xc�.sp���_���g�����@r�`��Q.7�qs�Q&5T�}-�!.��`i�%}4G��p���3��{K��B���}�`�g�3�Q�qa��4�t���5���h��)1�$�R��D��z5[[:T���X�sn:md���m)PI��H�D�T���G��n�����Y�sa�#�7���
h)&��`�+W"��:���al���X������QP���<=T<��i��C�Qx#L)K��"�5z��	72v8�n���a4�Ql�?��sQuU���YA��E�/��4��l���IO�Z{F���>��x�9����p��Y�"�k$�J?��I��J��)�q2:3i!�EN���o �W����N~��n��A-@z�)�����,J�r1���-��@Z
wc-���Y�~�8��d��D@jnWU�m_$�Z��H
l���hM�2g�s���o�eje
�j�}1�'�pX���E�f�nP"uw�E&�q6��c�lD{�� =������Z�A�Bf]v��.�$�'�?&�������"��3��w�KNd	#}��S��NH�!��`���w�x�
��F�����7w
Q��p�b����9�pB��7�-�+�#���h��z�1��������x�lA��FUo�#XP���\��������H�O~��"����/i4�������m�QC���/��(�F��	���Ws�6���W���(K�O��-�ut��N�B�nu��mid�>�1:�8�C�e!�.��
	&sF������|_�K1��9�?����5���T0�g(�D�^�� �Z��c��K:'��������I�Y���,���i����f�7eVw�/����I��s�Kql+������(���p�������W�T���"mP�c�o_���X�� ^�&���*�"��.M��L�/�vt���_��P��Oj�w��1�
`DO���{Z?�������R��}: ����������r_�r�N���:j[�<�E�	��N�0ua��Jq�y-�o����;����M���`���7c����o��:���u�������=%�D�����/-�������QfG�*�.����D�Em�b������1�w�F.h���T�w��c?���
�A���gXN�4��!1�/u���� �(�*��Q:4�����A�����P���R9BYk�:F�,�t��4������y���n�[Q�U�"�A��&��@8����!�9�����*�``h%�����2P����aB�B`�b��B����G��OF�|���+ku��<���K?PM�6y����t
�9�c������^����A����wsK��<������?�VE�Q2}`���������F]f �;�
�P3H�q}���K0�PVt/�)R�G8������A�^���;��UQ�����2����p<.D���D�1���*{oBl92���Md�~�q��|�st��Z��*��B)��YY�]���<�OM���T9P5�7�� �kJ��d�8x4M"A��Gk��A������df��`�mA9H���8�~/���a2W����?i��D�j@X��M�;h"�k�2k�Zt0����b����]cS0a�E�T�`g+;:�����Nm�L���0,�%� ���L���:TT6�TG�B�u���`�/��7�.������n�����Fyc+4���xh���)��W3�����>2�1�aA����>�I�d��c�ls:P�J&Q�d2��J&�����(>�>%�t��u!��GP^�����u��������t8�=���E>/���@4�^�N
����lMG�b�F\����������3
�P���V��L�"R�T�������l.<>t3�F9�WVE�9<F���:���w#p7���~H��X37%��O��)�i`8w������(�~ ��0���yF{�b���E��cr.ayB�g��+�h�������BG�A����5�ZL�?NA'm�r�:3���(\�����7It$S9�3�(�sO�Y(���zeW]`0����r�.�����\}��!m�]G`���T�#����b��fO��~g�A>Ei���"Fy%Xl;590��7k&8�f7�f�xO���i$f�7�=Hq<�'t�IjXd��<uHjF �RkNc��gv��%���f�����x����Q��������K�G.������P�����`�hW7:���([�W�d-��M�����������a`y������y�>*��z�hu���=A�[~�8�H��6����&~�M�[�CzI���������	e<P���<M��P�l(��F�

���X�9��E����R�\5�Z��\����B�������i&����YZ��ly`/��1��xkBa�
�E�.�<�����6�z^$��:��������i����F!��-�i*���%n;����F�P)aS�b���������~�[���X�n7��J���?4����kr�8�
|��*��) �X>��WwB�Sm�QYTo&O�d/7������Q�?�>�|^?����g��/�e�	���E>����z�:��l1#������`b 
�����m��O��K�f��J�������]�������e�v�E^m����,�Z�o�K���dK���a����
������p�t�����x�*�#	�S��M��r�������t5�7�w����
6�e�+�'��@(�����>�����e��%����m�h�9R@�(<h�
lW2Phs�������z���R@������P RH�z��"��B]��7���&����L�H�����:{�og��+����I��E����k�3��9@c���?d��9 (7�S����%c�E��8y1��B�
��B��(�kn����O�L-cs!�&��v������w��=`��x�]��f.	S�����������4���^@�B@we��H�g�{?��rLLz��fm�p���sup��8�Esi)��@�6)�>�����\����������#x�td�;�����6��%�uurS
�Ae�Di�0�0@�$|�]�G����$����� Ck�{z�����chy���V�C��tw��Yh{��w�m�y��n��do��6��@y�](�)���(_��|��4O���*n���X�sKN�{�Y/���7������vwq��a��m��Vp�����h��<��/��*nA���m�:�@��z=����I���&��.{\������n������x�o2���^���+������ ���xh�z�R�F7	}9�V��O! #�Kb���7]
�jK�z��!��w�����#g�.gh��D����8@�� bJ�+oj��Sl��FG�����IF�J���?��Ne�io?
0=2����>����&��=%#P��0J=�s�"y00:�������a�G��)��(�H�����>��h��6��4�7B��f����w���t����j(��vO������.[-��^v��
���=-�����}�]�.6�v����U�/����NM��3�����������6v.\�������U��'[�0p�����#�}]�!��j��xIm�6$��\=mon�������@�������6V��T�=��MEz��6iz{��po��L�����a����l�'�O��������t1FT�`��{�Z*s"[�\����������rr_�6zh��s�I��8q:6�F�@�n��`���xH���t��Kz,*��FB��w@����nPD��r_'i� �<w��J;)dp���%�����/�0!/�kw�����?/^�M`e�dc�7 ����������/)�P��~���S������QS�M�����~�|�����i�v����������f�� ��w��~��/E��?}��9��"����vE���xM�~�6�����������\`�#�/����<<}^��h}�����"9�'W���f��6�Z;�%S����e �/�����i��L������o8��U�{�A��
�{d�A����3{W������w��������a�?M(�0���-���I�s{P ��9)�+ ��p���
���c����?�o9u�f�{��8	��QVv��������s����v�z��?��g�������k�����_~��O��p�����)��'�d
�9+�c��8R��������\��Q{������3�����
��q�v���XZ���H����'�V�U�6ZW��X���
]�+��V�[�P��h�~�,����������C����L������]7�����!p���p`@MxwV�f;>p���gpr*����	t��.v��������!��`�u��Y����y���V��y�Vn)��e���
�m�I���7�����X��:�i*k�L�2���<�4�:J���J�}w��X����r�~��"�8~�|�/��8��O`����*J�����s��.��{�^UGlW�L�lc�J���3My��8�e�[���#�jk�2����`�������v��7-�+�G4��y�5��U�kLJ���L��>hg�V�=���y��r��>d�G�{��<{��i�TC\|�=n�W9�m&g<����z%��5cg�?8C'->�XW����Jk�i0���)����Qz#t��`0�-���e����	w��.��e����A4IDk�l������l�Z��w+�e��x�H�.�3]&9��-v9������ZS�s|�'�ls�|�;�Lp�>�^�<&�K�r^J�������[�}�������3��`��S�}H ��r���^���]7}��W�&�W=C�������9���)!z��N��jc< ��(z�C����
ovmo�0���8 �~<B����w�8�O"��:��M��[��4��$d-��N����Y`����%2��	��������X�%��Kt

�@��C���K������I��L�����4��L$�`H�V�c���qqR�*�l/\=C#�CX��PrS�H�^�����
�G6S�zJ����n�`�H`��qQ(�{m|�u�T��g�P��6����p����:iZp�efk���eI�u2�����AL� yv�+1���n��kW]���Q��[0���((k�7/8I����.?�'S��K�%��b��]~)O��h��	�8h�i��)}]$*�{���,��vP��o�xY��2��������a�����O�������>t+�9��YV��}��I�M��e�������=�����r�v8t���#s��W��DdA!�����=�����w��A/�aL��f��r0>:')CHlr,��,w��N��iz5i�"G��T��gt�4�����\T�j���/T�[,��[��_���u�iQx�*�d/�R��&��M�hi���9��H��$��v����T��W���8r��\|
��`���g<E���L,-vN��S~)F�
���p#c��S�T^�3�*9��
z0*3�N��z�E_W-I��8{M���!/�~$o�3�g���<�e����p�H�g^@�M5)���k�D}�~h����o�LqP\\	f�^R�.i_�y�cjB�l,E���?���>6��U"I�2������^�2i%�S�����,�����NU�9�s�}��C�N`���E/F�nWcW�@�]����m���:;�%3��I6K��5km.�����*UF������P��@SJ��Z_Y����ke[��}�k��t������ �L6�p��v���e�������;��)���������%d|h�\�PN.�^�qy��L�Z����w�%kAs���o��������k��h$�Y��h��x�@dI�`�(K���a�E<���0���0�|����W{fH�?�T&���Q���/��,���MV���Z�m�P���������^��(��g������Y����{A�]��RR,<�
�Y��A��NzO��qP����`�?�P�B�bY�����-`X���r�!��i'C�������go���C'r��a���������M��6���6�u�V@pM2��H�	��p�Z�	������8�&�|'3�����UvH&������������}��a���Z���3���_T��[~'i;��A+����+ZK�"�s��KU
�e���
H4�����������L�����Zi
O~u���$���N�VhlA58������h�0���H�XPp)[�(���<u�r���0w,�c��tc]�G�O�l��r'3�0��qV����hp�����@��[�	�)�)��������QLkb.5�K���fn�{�.�l=����=I���z�N��NJ:z	[r��<���"9������2��p��H�Gec7�����	����e������PY��v������h_�RYb/G�&O�&��O��4Q=����Y*\�Ib�7�n�T��p.=�
�kM��
�!J�W��M�d'c�ub(�F�^NR@R�teBY{��%���C\�+����j��Ol��&Z�6LR
�-N�0�}4�U2�bA?���%8HP��6���/�<i�������_P�%md�h�P�Qt�oo�u)����/3*[�����nW�����gT�2����E�%>��V�D�N�a�\�-�2��_�����K]Xy��!�����*imQ���s��1�a����]�
s�S�Tf������W:��AOTe�������U��L����m���}O��mW��S�\���Mi\f�J����	f�rz��3���hv�cW�����{L��q
�G���:�N�F��+��Z��W0wz}�}���7��=�G|�Zi��b���t��~��f;���.6�ld{1I~kj��s�����������Pp(Xr~������� ��[�|�-&y�#l��id�u{�})2�C&�Nf����$
���k-����a0"8���U*��d��$��ZNi�L��$��-�c�2F�K��u���Z���(y�b:c0R�k�%��0R�
d^�!`��Q&@�����v�]"����pe�R�+�yfp�T��7[��>�^��Wa����J_�[��2�z= �%�]����u��S�����#t+-\g��b�)�DS����DW��K����q$Y��y~��bw�+6�AR���(R];���bw�^�"��x1Y������#3����������*��nn�c�[��N�&9���f�T����U��R�sR�(��D�$s��C���_6��-�S�)���h��0A�L��Xi~�$�+ufc_p��l������Y8|��.�/���6�^9�����pPRv��G'^0(�^'z�n�����
�u_�z� ~���&�S��.�&'l��h�����4�}iZt���7��uW�9���`3�N����F���p��������w�y-���V�+B��A�����t��G�;�g/_��5������NP`K ���	��~��^��/N�~�#E�H�C��;%���t�f�7#%%���J	+d��O��}5�Q�/0�cb��R������ XR��(��!����kR�����neRM��m�����e��Z.S��]������S�!T-c��}��r�:q)|-�?��*��?����������p��3���Ytx�t�'�J�'��Kl�f����q�����$R$�g��u�����.�y���|I-�!q��c�'�0���:8_�l�"AX8�W�R�����S!A�o#���W7�b�����5�8(��m�}?����Et�y���''�q6i�����9����s���5q��/�AE���[�D%KQ&yU�+R1��q�b���O�j:���)Spe��,�]l��0Lwh6hPb��h��@�\��h��9�8KK�i�������#[����_����{B�s���f��-�/r��<�w��f��v.�6O*6Ur�`9�Tb"�����K�M�[���<uNH��:w�����^\'�I���b����Q�\��*di����D9]�w�e5��X��}7�_x�7����RN3.�P�F��;Q)]�VT�o
W�U��M ������������������`:�������V��WY''�F��,�*b�TZ�I�O�`����������+
��30[8�}����:5�)���(Q����Q�j���$2�� $r;�(��s%!�
,p�)�1>X4U����B�w�*���}����B�b��R�cq<m-�s��+���O��D�N~.�f:tXx�a�E�]�b�i?0�"1�+�������n^�>�6#/h�<I��t��
����h��#�xI�+�A4�b��*.�cV�����L��p{�a�el�I���<�O��<�	sS������:+�R�CLM���R���h_�_��>��U+n`*�����2����d��5��>������mrm���~�;�H_��Z�OX�i������B\��Q"'�]��I�U#z�9V��V��.db��Y�g��P�����o5����Q��c9�6Z�K<�;g�r�}��8�$��$|�b�]_b�����&���e�@6���\0���� �c[�����1�I�.�R��� s�*�"����-�A���`Sm1�?-��n��r����7����>��+��K� ���0f6*8$I��^��r!�M��M�7v��yH�d�j��k����*��M0=��Rh��k������~:�Q�B�/P�-�BR��78���S�J��}��J��{��J��0�MG��j�����B.-c�J^��w�9N�q��&������bP;v�pMm������	=0�Z0����B�������V��g�hIpU?����=�U?��K�V�t��0�<��5i��1�j9����JTB���-j�'x�
ne�����9T�o�xr��3.;���t�B��Jq�<���"�!Z��bL�b�|*+/��7��8'8����h�l/�v�j��� *.����3��3������[�\�ya�&y���]Il��]����e���Mg���-�y�
^)����"���,&�$�����&9��� MUA�M
�*�^N�=�eLB�G����
�d���i�N�s�����O�a �C0$m����,U%�jA�(TbtG���7"�~�����!�\m{l-U��*Q�Ow��	��?�����3�T���l-F�Z#��fUyv��u�L�_��\#)d:������D=yR�K_�x����V}^�2r��&�d�q���&�����2����mTw�u���9��uS#IML4��'����^�8��gb��q���c��;�g�=�Q�K5�EG�H��_U��4	%��:8�Id�5)���|������P�'�Mnd�4q�_��{nA��=��V�*����'��tG��)Q���X(��$Q[�A��$/T0?�+��y�i3R�U�1��v�n�.+����v��W��9)�o��������n�<�l��YU}#Z-���&���d��X���*:���{�n�i!#��d�����W!nj���#�� N���pv�P.NXG{D@����3 ^*T�t��q>����bsw�����l@}�>/v�r�'�T%��=�����*���#������7(�,b1*K�����V��d:%�_$7?]�\�?�n����!��,(e�&�������:�3Z���%Q��!v��C"q�q����{���(����?�8��`������\	0�o.���j�3�J6����S;i��e��:����d�q�,(&i���UR,�����k�F��@E�-�����>�!ii�������-#�^p�}^�	�(P�������)�@�!�,{������Rclq�.����x����Tp`�V�R��j��,�������������D7�g���
�y��W�u�%/�m%�������`�+��1���ee�[e<f��l\~���-�S3��+�*Tl���k�����8gVr����p�;;��1�D�gm�)`a�M���6a�U�A��Bd����6(qm�j02�h��U�Jm}_:��^�TU�Z<q�R���.��J*��Y���4
��p"��K� ^^����4:n_vY<�<sq����%�x����e�����]zk���v�S�0��T"\"J7\�JA��2��M`vV����5�=��i�_=�4�e)�q��DG�bq���[�
(#L�\��E��#�T�,�������A������~J r�h��"h;�i���M�����Dy��O�<�����e��w��ODk�1�w�2�rH(i5
�bl�f��*�������G����U�����r�GZ��gEF#�a������64�z�N��H�Q���0|�MjM[^0
(��o�s���
�!4Z
i���l���b6)����F�z��r�ej���<�pU\��=
��C��������l\r����4:�.�"����b��\q�����`��`�Hv����c?�P�G2Iy/��V�9G�_?�<c\��:�����/5�Ko���Bm��E�U�6`����:��X������JA��VW�j����E�������X�,�b��n������K�����&%s�E���Sl��&;��������j��u��`�<i/t`O
k��S�b�t��[�i�2��c�3�b&�,������K44��=�|�=�����pb_o���8�T��s���Q�Z%O�5 ���b�������W=8��\�3����wRdkQ[V��+:3(����iq���f�p����	����
 ���%al��L�f����Y�=�"(K"�	�����w���9=dP��q���!�>*�9M�&r� �j��^�x�����Z��e.��i|a��\
���_�D�#yai���#
�HbN
����DV��:���Ix�'�����p�k*���|��>!��~L�����(b�eny�����c�P������mc�<;�7�Lu��P,&�4�h�X�s��9������u��B��^���0�c����uv�4�dRs:2d���qbN_p�&�E��i��	��\@����,�|8��`
k��9��eN0D�Y��=�I���@�9-�u��r9���"j1����wB.��A����p]<���3A�L�pq��WOL��0$@D�X�f�� �UL�j�$	�����j��*��9�YUoH����e���6�7]�C&yY��a?�&I�;$�
|4:Y��\��,]���p�e�}�&*�Ie�+�R�K�C�=kK�&}w�|��%��u����������nZ��*j�~N���<H��MZ����p,�}�EX5H���R�����
3yEW�D�@�c�����Zc����!h��34��x���;QPE�������l����������{��d�����Ln���9�Z|�"E�U�]bf(�n����eYy|k}D\���������M)e[�={�U�eAl^��LSD��o��:,k�a[��P�rm��CW���.�f�����j�&�^����;�/�����Cn-��%���G������z:e�]"V���r�(����5�������+Qj
�N��e�����[��1A������X�H��v�m����0���Qh v�mp��_,��u����}��)E[4EQ�8�*����8g3�|E5�g��0�U�y�C���W�z
�d��Q�t]�������U���r��(a@��tZ!����*������_X�|-��I���d&��
c��CXI�0y��'>��b�BR{��S@�����C-�h��	GZ�><�eV���?��aw�]ids���
������k%��������d��}���BS��da�3;�jU�`��b?v�e	���	�=��~�{��QB��0��/�:�M8���&����J��x����c?M�E��V/o�p=M1o��a�a���#<�=�N�MD	HHY��tK��\��lK�Zj�L��nS.����*e�X���n%��������t��;!�G9Q���W�����r�@����������e�1�zs����(s[��%��������J_S�Z����H�u��a�4���/4D�����Z�%,,�P�.rn����$X�|�2=�l=*��{��r�h��C6v:���5N��#�:��ic�����Fo�����u������������cZk,"��,�xJ�Ei8�� ke'~����Pt1������?��Eyg{�s.���q!P}�NN2�p���\�c�&n��k�M�����
���[�U�H
��j�r����n^�~7Z,��<S!V�/�\2�����b������[���7�E��{`^��L�Gx*|V������q�aM\c��[*2��q1�+���N��r���l��G���e-|v�l������\� �h���Vn[Hkp�.���S!.Lu�(���_����^�p���P���T�W��~;��XoI�c�2�Ub-�zs�&c.'������j���Mg�R9�\���H�o�]���X��b^~�|$�w����<�E u���
�K��z�F�2�F��Y�����
���j�+��z��:1����WQn��6��9�����i�!
�<~�)��B���V��^�Yu0-�������V"W��:T�1��	4:�M�W.���"������n��d+1���,}�������{�����Z{�SE�&���EfA�O�	=�4��8���!���j:�(�<�0����|.}�2^<;�L���)e���|������-�"��c��N�Vh����'���b���\1�Tb#���6eFy���R���������.D���3����CI
����1���8�i��]t6��������6_=�q�x�k�������^��8k��o��7j�y�3jS���F��q6��	�~L�tZD��w�Y�UO^ePL��4Nw�
D�����;�F�L$��,�<KCp�8(��y�6�K����@���F��G|o;�����e�-��1�e{����'zn�"~J�V(]>J���n���sl|������L��H���y%��Wu��ti���W�Vu3�T����������������� �i!��D9�� =O�F���1�J�#�`%��!�?,�	��O���A�M
��SU�HM��|���u[�t�������_�]�%�������h=�����B|.���5@��p����+�1R���d���x�n�A�x=2���Nl������n6���	��U��ga�6�(>������������VF�0-YF�@tB���I�9�p3y�hb$�L�N7FWhbwb�"���=c_5�8�r|��+�j�����*����S�C}6��.�Y���wD�o��m~#���G��_a�/0O����<6��bU��In��>�t�eV���~!��b�����,��e��z3/�9�U;�7�`
��h�L�v���h��`��T�����ea�<c�H
�4gh0]8|n}�H��_�\��_���s����Q�^����[*�6��[*Rs�u
���	����B����i�����8n�����r���L�d.�Y��=�,}��6d��-+MQ���(��!8���������,��q���~:F%�GA��B���`H���sW�X��7�M�"Z�����&�i�J�O�SC��g�6�L�)��w��'0�� ��%&
����W#p.�4���|�CK�nt��ig��1�(6G�"����;����b�] ,��\(���O��~�/������z�y~>��#�Y��u�~����3�!��@e�1��|W>�����~�e4���F������9�9LU~�+�c�c����k���2��6�R�1
������a��Pk��������z�:�6�"�/@D���L�(���\�Wf7b$��d����L���H)=�	�t7eLs/�v�(�E��e.+����Nx����c3X�U�w�2;��Wc��g���(�^������������"#�����&+��v3�����
��l��OG����J)�19�6���� %��2Xp.�EJ��2u��*�����\L��V�M[v����%,�*�e�Z�����x�t�%������.#lnK�rq�����������N4E ��s1X��e�ZaK�n6�y�f�8K�rQ(aW�e�����$��W����_�$=c��l���h��+�����������v���a��_/W
�[6��-w�r�6�ZrA����>�R�Jl/�����( \3I�/9����C�Y�eM5��+�* �2�Q$s]��+^3 ��9R��i���Y+����1�S�W/�
'���{T����������\�Khq-h4:\l��0Fk�a�;�VjX���>��!���"`}�;]���9���A0; \���TM�FZ��i��{����\������vuR1���	�U���YN8�gQYl_�	�����@�p"C2zx\���1�Fx��QhG�3�+Y����G&�%��9���rq��J����bX��ar���
����B�"�y@1}���t�Q�?�S��:.P�j������EF�
e���)<�P��.~a,b�9o'��5���
��I�E0X��e����%B�B�&����|��$2'Q��y�M(8N3����n�l����Tw�k�%$.�=�>�{�A�B�e��G!�i�[9���x��YCK���Z���j��aD
g+-�\���6������8�k�.��*��� ���<?"����%"yh�u������LE����*#�ZM����8�8i<��MO�;jf�kq�#�jOK����v����d������L�i<j�
�NL��S���"��&S��6��/^{���E;]���L����
T�Z�1,F�.����Zf^��P`��L;�)���7{��:^�K�����B���$A�9z�t�����vk����9H.�����B��PS����[�l�FKl���y���4�}�����0O��c`�����i��OD	oQ}�P=$
����Q���`d�V�g�<
�j5-0���nK�%���0��}*���N�H�i���[;�r�t�Q���\r���JG;�t���	%�Rz��o>�|�����.;�C��=�,��Y5B �����	�o�V��9y�B<��f��0���qc|�$?�Z(
�kEx��O'M;E.+��7�O0�lS���8�&uM�'�mR�P��8�9�,��!��&���m�5���da��at�K�����]��(P�U�~�l��N�����N������������AB@4���6-�Y��-C�4IAV�ql���a�I�"�(��L<s�����X�$A�j��,Le��j�]J����	b����zQt@���'��;9����_&��'5���=���0	�8��G����R%F�1����������kUm�tj��s��N8�fI��q��d��� �g����y����Y����������[$�|�L��QQ����������� L�(j��uF�1$;9�,>�2������7|�<~��;
)�:%���-��0xi5���Q�h%��j�>����/t��:��9p�7
����fF�m���w�;�S���;����0je�y6���b���O�q���d��8RT��^&���.0��.s7�������t�:\��1�a=�+���5a��Y��l0���L���\�5P
�!
�)L���eC��Z���Idj4���0�B��1�>O�������p'��p8��l)�&bEH�Q���R�e���?���3����Ymf�j��J���4��pS�*�[��O�c=�
&N��$�q��H.���6������(���v�C6����IJb���w�W��NF����L(94��s�*�p�"�t����~3�u����}�D=M��'n�R��(N��u�'�n)s��S�%J�qe��1(�MP�'xpJ{c�����p��,rU\�WC��rF�r�������=
���q��W;��s������MV�bP5d&����y�I�uj���ElO:t�[�z��dVL����_�e�1��^qa�l�he>�����

7,�����s��g��d���Z�>�Tn��M�.�^7a7:T6��Na#w|�aDM_X'A~P#B@�1$��V�K.���r�i�HP���V��@(����~�������^��ga��E����9HB�	?l�B��(W��vtV;'o������5�F���B>�b����v����^��������^��PA8$�'��'�(n�1�����oQ��=+�4�H�Z]6�X�V��B6�:-8K�^�� ���W�p��#��ie\�67
��gA�/U-�M�yJ�%V��v�������2W��w�/d����,4#:�����hjT�h�:�E;-��8��
��aX���d��`C)���c&G���x&x�].��:��UB�����'e����I�����l�Ev��H���N�����,v���S���;�!3��\P��Q.(}�r�T�`���\0,�cl��[�Z�9F�&��FYdrm����+����``	o���������=����>�.A���������N;!Q+���h�?=���������"\t����c�H-kC[������A������c�e���r!K|B��&G.�)3��XT3�^L�����Nv��V����.7�/&��)�n�9�=�_���}�r_�����r��j�	������u���$�r�W��'���J�3Al>P���� �v9�����x��<�t���&g�E.��������l�C�M�j��?c��g�������]���P�#��!
r:��`�����������/�b:�����AJ��F��C�08�T��|9��D��0��@�b��F0/)�r����P���M��5&
��8Z�2�B�V�>���B
Tb~r�5�t{�a�.�v�����)9��O�����"4��o.��]eb��"��)5X$iN�dl(�|3�bL
.����d^�>��l��12�L$RU'1���
a�op1���KM�� �H��!<��U��TA���"�"a���}6|���G��t����1*0�nQyW?H�YH�<�,P��d���F�tO�@y�<<np>a��p�����g��l��i�G������?���B������/��]!C��vq�5�(����Wb@E����j���e��NH�{p�����\Q�"&Y	���N����c���.���X'����(�?�	�����I"��� .��b�%P��2����d�`�Z��,�Duts�?gT���,�Z������@�pFw�^�?���?��&g)uW40�4?����b��QP��V���x��������>��&�Y1���&����>�B��m�[f��1^�k[���o(l����������A����)�S}
!�����P�y�����9������7
��P�������#���Q>OS���~ipZ7R��)��'�[o��B�gC�� 	Dr(��1��I*i�|<��sav}1�NJ�M��B'p�A*���d����i��{\�F�:������-��]�^����,Y'��&�.�aA�>/��\p��Z.H�2�.(��>�BM��F�r��P�\���7DQ5�/]�4�bu0�C����>b��`s��0��	�9!�P��	b��s1Lu.�]`��4h3]��W�-d�VGA�1L�1.���q��
ei.���"X� f�������3�{q��[��0�x�����URGU���B�Y���}(>&{#JayNQ�^���$�A�~?��Q�?��c.���W���5{f�.Q.�b�����>!Fz��| ����%"�b�G�\�`4�l��h�'$��!� �	P}iC�A����T��/
.�_mH�A0C�'�6{�����X���%6�	L�G7Mj��}8iw�Fa�/()�n�G�5��]R����e`��a��%&��[�k��;��&�VH���"�CI�A��Qr�����n)
������"
����X7�>&�Y���c�}�_�(����,���7��Z���_�����0���Al�@6P�kAM�xl��H]�
_�	W�=�"aN3z�3�\�0PMg��<�v�l�,+n��^l��^�&�4�����E@�(,L�s�C�s<�dW=��5�"�k��[8�!L�����L��A�����r���E2wNpQ�Dg��F_E�R$��/z�L�$.���,	ks�u�f��b%�@��u"\ ���fJ��#]��<�9��o!��.���"0�m�1�_�a�M����y���Z�"�_���(\�DpQ"4�@rJ��aro!���q��*S8��Q:��C�{�!��D��a9��sS����K0Q�����y9�~���Ct��s�y��F�!~PS��F1���(��.�J��y�Q�����y�� ���P�d��S�l�Y�3�R=��M3�k���jBN9���[$��.uHrq��[��0��U��0���'];��:�A��\/�u�mg������s��
����4����1uY������z���^�����2d�����FV����B��,L}V��CX?��A����[�_�P
R�O%;w)<RW���#�S����KA�}���"���I?�n��zV���\�e�Y���C��%��\��X���q�n�0��	lK��gM�����
Y��_���XE.���.�&O��	�wE���O�U�
D 6���`|�R����w��0�mZ����������������y
/�{���i m���?������u�/�'\����w�~�����rHjl���C��a1�m�a��/�l�{����o����/�z��8�n�����!�����rHjM�=�o_�����!3a�������t�]����/7��_��a70,���o|��������������!��)��������+�934S�����Mk����+��2��l�w���2^o�7����uY��O7�_�������Y���&g��m����'�p7���S���o�������\?��Qz���jW��������(K���\K����k���^��{��=��_�E��I��:�������������'�B�l~�v�����7��[���h�r���@\�zIp���9W0��y~��|�q=�x�^������+v-����&w���"���-�~z�
��/6������X#n$:���IU���~P?��>E!������E
�����Dq�h�q�X���������^�z��������7��W����o���z������k��u}������x����~u�~�[��C~~l�5��W������?��/��/��������'��^"Q��R�{�����EE�'/:�����K���";��j�����V�� }�%u��_�9��W7��xP?)����V�5��W7W�n�]��T �^����|��S��d���.n~tp�WQT ����P��n����r{ g�t�	��H�P���Z��
P,(L���^��#
�i�������o~����>?4Q�V���n�����K�����HQ��������v��JQX�0�(5,@��P����
�"�`��^�	@.�9\3�p�A�=�n75�F^eF����x��
�P����1�����Z0~ifz����-�6�{��>=^�^����<���:�`���3��H0�T���(uR�Q����� � ��}YK��=���������v�c�L(������������K���:����5�"��������K���kf�=D���(-/���
����p�GV��*	Z�3j��i=�D�}�K�{I�1���]����&7#�ITu?�hPCv�������7*(HQ�0�M���W6�jb����W?2Y)/��-���@�m���R���7�d��)'� ������?a�#��mj����7o��6}K�&�/o��@�tS���0�������My�����]�=��}��]��u|��@RM�m�����2��\&���5�~���iy�o������M�� P�6���%�b��u�WcR�avf��^������#a�	���Z��h�x�:.�
���m-��-c����H}H���^��7n7��sT;�*:F����q}��kC�
���!�7��v'C�kG�`���v|U�V�����p�J���F�Y���[�El);<M_;~0�0�|�e����O���<��^;#|%���&��APi��X��qs��_k�hN�������-o�Q�(������z�vW��Hj��h�2�<�V4����]��
����P�_��L�����
�'�����[����I?Pz����V�U���??�*x��89��`A\9�A�=�{T�8����l:9�,�C�O�<���Ae���t���+K��+�Y1�j�Z�*.���bmP�@3���&Q�2��+��t�>��:D���.���\�����_����I���K"@y(�����/	�e�9����]�67)Z�#U&h��&"_�I��0:��/
,���%�R�jG�g���M��^�����u��Y��g8�B��FS��+&^]�<��6.�]��C���
�r�BS�s��k\KELX�A8���������5��	����M�viu��RN���GD����#�Q��_��JrW
R��@S�&G�HEJ�7�H���dt�-:�|�~(��x�?����?�-����`_��
���[�0�D�R���_W�A���9��-a�i�x�����o�L�fK53���v��}�U��qQR���"��s��������#�9GG���C�@�����6����J���W���r^`�f���F�-�\�H����C?M����[�n;<�-���j��.��j����D���P{�@R��%C`O���u��Z����F�������EY��R�q�{BY��Q2�m�7n^q��Q?:-����~t�[A���pDi�
�XAVYX�=�����jc�����kZ�L�5R��>��l�G��f,�	����D���{;��s��vG�$D�y��������5�>�����e�".���n	����bv���!4��(��U�����=�G��?6i48��Sp��>@}�CN�r���,����u�ch�+�K}R���S�GJ*��Q�!�<��<Da������1�1:a,������� �����q�#�[p��4��w|�}���1h�|/��0�]Nk����<cs���+��6m�-��P���#�h\A�E3��>YX����U����s1T7�xg,��4�X��7�v3�qIq��X�uU+e��+T*�:`Iqp�lO�Y������������=��t�TN+ygLY�����%Wy��LY[�lE�W�����=P@�3����D�U�OS+�0p|C����9�H*3��[�l+
�,�r%�����A~�!��b _��U-}�U�Z�{��-�����{Z�}�G
�����h��6�����u�N���pl��cg����������Q��u'&a���Wc5���,x��Y�GkQ\����o�IA���O*}���6�#���?�"��G�O�f�dq�,)�x�8�c��:�m�;������T��z�<��*�#�l�����p/��_?���!�x�Zl��O�2T��� *�����Jn���RTr��H��
��;�b?wi�G���-�7������V�#HbT#E+�O�gX����9�����������/��������c�!��6�p���ky�����Q��Dk��jD��0Hr|��A���Z�uh+ewF�����sH�~ ���3�F�w����W�2����0�ook��jp�7���r?�9��r!k���]����3@7�VzK�V���43��+#�#<Z;������	nD'fEO�z���;����L��������
���+0
����5v�x�d��;�>
�yde(����y.E��v��8>P�R��WW;��k�������&���3���b�5��D�����<+�����������V�2�gu(G�O��������u3[y��	��(o,�����/ ���m?NV:�a\�~��Z��T��I�0
�I�f�2x]�|�B����Q=$���BhG��I��,�����L��/�c�]�
�AC�=�Y��"Y?�=vn}�?����[]r����u�z�#�:R�]�G�AYm�<�����)���[��A���:l���	���A�j9�1X0���e��9a<�I;>��E^�(�%�$w��V}c����;�:��������q��5@G���j$�	���QM�l p��@���I���J�Z��/�����I��%����Y��=���;F�k<��9�-���b }@.��/��"E�
'Z�=������SNv��j���a���E����./�q��4���6�4:x�m{��U��������'0����#|��$��Av��oXDm#�����60PR��&a�
��0q
N��G��pF��L[��;2o`] �M�6��_9�4-s6A�������o]�����{�����P���DB�K-��`FF�(�.h��:n*M ���&��9X����t�q�?���U<�.D��<n���?��q�'Fc"][��!��a��b$2Z��8�I�u`�_�iT*F�7���������WT9o�����������5iA�q����t�?�=k������3�E�(��NG�aWa��Q����S���SV��C���-���")����)�A����C�+3J�9^����iQ���4qX&�|�#�(TP�\R��;x&���X@0+7\�K;��b���UrU���g���{��q_����v����&���mO0*
���vQK�x:�b�-q����>��3l�F)�����8x"���/6Y)67�����)��q�`p��V�����O�Z�g��C|�v����������4p.:�V��<�4g�N�}��K���4�5���v���H
�����JUa��=P.����p4�F�Cm�1�3/�����m)�T��%uP��>x
Y����]?Q���C��f��]���i��4�W4U�� o;�����f_�f��&���h3��c!������VL�II�UbKd�L�|���{��E~�6_��-�8Iv
NJT����j��L���}�AQ��|�������u�G3�����m�"�u(U��
�V��8=�(��D���Vn���3�����+,=`j2W���zK�[l@���.fg���z���oX.Q1�����&�����6������m�c<�`��\S�	�
y�x$��&2�{xk�C6��G:����"^�8$��oGXY��������1��v8�Q�8zr&��
A��T9���GR�Js�C32cw��1�s���-8��4��*-~:Uy:����#�>���MW�B� ]��I���P�e�OF]r�\����?P��s�����m���o����YZk	��?<8c
��6�2���tS_<������}�T��t/���8�O�gR���LD��P�J�������^b��.�k��l�T��z^bG	"4�I�c�����#���Z��s������G�<>������,(R?��#�)�u5�*3���Se�CQ����9�q"pn��������vE�c���	v=���@��5��d5��o'�L�l}�Ps����Q���1U����6x���jy������(�l���h���&��������jg���N��i�_fW�&@�t��������J���_~��N����L������O1V�r�!�����U=(F��f��3�d=J���
5�5��K� ��Z� �$;x�`���t�;M�\@��.�G��B���_����XQ����S7�u�jp�hY��m��g������/K��D��j�zs��A
==1h��PGe�t�o�?By�	}!�V�l��,M����o�8�:Xw����$�8�K���"���Yo�J����������o�"���;��9�~I��@�x�p;�p6	�������W���7rN?[�S��*��	���>������n��{�������Z��O���n��7�����������>�Dt��t7q��A-����[���]�%�����>5���~�z'?����>���'�1��_�<{����k����H*"��g��">'0���"�V�������
V$�vP��aJ%s���|��W��'H��(��4ifJ������#����3`�y���x9(�I��q���.���������&Qzd�e�~A�\#�
�7YK6XMYXG�d����$o��� �;,��ijK�9I�0
�K�U�8�"#��c�����G"DI�c��AP$�R��JhF/�G���5�:���z1)� Y�OyX?��S�������P�j��B�����A������@$�o-v�:[�6��vS��R����o���x��>����'��ub����.^Yx*Bp0fBC����E�T�s�x?����W����6�
��������~�d��$�\��w&O�Onp���N������������K�Z�U�	�r1T��"*�P	P`0K��@�������������Z�#m��������w#4y�6�jY���=�2�R�m�<t����2��m���~�]�"���A>���j����u��n��"�
�/N:bD]c���.�(J�����4�U^RZn�.���j
�B��7M�2"���3����t�r���j��v]��!���V�9�v�H�!�E��d8)�K�����l����y*�������h����~3�k�W��~�e�k{<^�M�|#����G2�%�$���5>�PqJ>{D�:����):"�����"3���} �9�l8b���#]d��?��K����*�����+������g}�M*�T����6��?���l� ���������\�	���%�G���#��Hr�K������y���.�sk��s����0�y�P)��>z��"|
��+<���_�$>	3.�1m�Ty����a;��;~C�C���I��?DZ�0��������
�O��{eFp�v���b$�MO����K'^E�����%'9�t����J�
��0^��|N�rX
��/OB	��m�|D�g�6E�y��$���dx�����<'n����c7�#G��Zs�fn�!_`�;��j�.�`:������a��'�P~X�����,C���;�+�(��
�k�@t�+Y��J:��|���U4q���F��\sg���@<s�A�qq����o�Y�}�a-��
�X���6�q��Rke�N����(�x'>h d[��:�N�^���g7�"<���i��5����gC����#F',:FW�����&~Jcy8�������Nw�k��Bs��6\��4����M�f�N�X^�C�����SJAba�]��q�/�on�7��r���-e�^i��+��[}W2���1,�W;�V���#C��O��zT��������+2� �5E>��>~��}R^	��Gu�~XL�=y�C�.�6)���vX��%��XE�d
.p�YU*����?��Q`�Jy����Oo��8b�	7�H���jN����7�Q'5�����@dQA�����s��%��>k~,���`�]�#P�!�/�^D9�b��=��o��T�Op��@�e���H;�l�yp���u��
iIU��s�r�/I��+����4k�t=O��H�P�?���j�,}l�?>R�.D�z��y���
|Hj
��[_,k=��f�`A����B7�W�q��4����vRjk�ETzc&;$���w��0e-|o=�Q�	Hy{k�;���Z��$)8Q�;���,�X���-�s��.>��x�^u�E���,���[��4X���'�t����W��	���9��$"?�$���^�
UO)��%vD�|��,�{��r&E��~�O�����q��w\��q��I���)�M���3`�����}�a��{)/��}$��=`[��j�8�/b�(�C���4{
p��������H����S$O�:M�'��3*CW6�D�W��0P�@��HL����X�����G�1�����g���W��p*$���I�2�qQ;�yf��IV��O��\N������N)E'��M�+6C�r_�N�n����7�[VP���:N>����n�l������)����H�h�%���tPP$�[E����j2+r�F��}�XI2���I���/g��l��4��"�x{TNn�>����9���k�v�k���FVQuKI��':�C�����U�`=������e�h.M�w`1J5.���,������>�p��������u3�$�f)�@���E���i��	Q�O�"-�A��������C�a��>���<t}������$�1&�!��=ay�XB�T�a;q�jA[T'�)a(����KTx*q�-����	�2n�*�:	�G=�m���Hz�!������n�}�-�����SMO[v�^�Hd�7e�* ��[����fy���I>a��}Y6I?&Y
��c%��'���m��-����f������$��_�,
*%f���wNi�{TR���xeU�3�)$4�bg���E0��<��vw�OBp^���}G�2�`�}6T��k��:_HR\gL��G����4�����en?X���DL�!�b�I'(���;O~��������\�@r�}���OOG��q�|�rO�F
�Q�
u����,�E:7�,P	��w�H�4��;����q��p	����)w��:�����{[���Hm���	6GU�����
�)��J�>�����TA=��v�i���	��7��@����E-�	mK�}M����o�<���	;>�M:[R��x���4[� ����A�}�����qN��"��
=����X�_=x�i��W�}��;���WAT��0��,'M#��m/���Nx�
L�{�{G���}L���}0^��S<�<5�P�VBp"�z��������n����Bd�3�4G�
���U9������Z�����0%L��P�J���$h���[��!sz�;^���e���cQ-<*��E^d����M��G�!���������&���6�`�<^h�$�+���NtpRA��Q�������d*��#�'�����(�s�W�6����LBs�|2���&��p����MM�cS���"��u�,>}������Y�Lms����z�T��y�S�KWo�[���%���e�tAW����r���(s{��e��*-P��1H��M(W�P����<;hL	Ocq^M\/�4:*z����&1�.��i���f��[6����i�8K����Q�� Q���TYKj���B.�;v:�u�xT�1W��l!k<�%9M]���?j��TC�ClU�7�#5�����'i�O���Z�8/�5���H�/��[K��@���,���BX�X��#��� J,�9�r�oQ��uN�#Y(v`�X��Z�
x�f��*�M���o��Xt��ED++�k?��Y��!N���1��!$4~�G�@�!1up>�Y�M�U|��D��[���tF<Q�(����*�~4�KQ�����e:��T�}�y��yRP5	;��n�<����B�+$\�x��k����x�'���>��w�]�}F�L�!�S�`���	����N>�b!�Ha�����`q<K��|����*�2�x��{j�F�@��~�0v�� 0��<]�����s����d85���MS�	��p����: xxX�f)�U��<lK�A�_Qp��2��,����~.������=O���E��#Ur�~6T�������,(�lA���
��v� y]���)g ��d�?���;��W�����_M�k�e��3s��IP��*N��Z���%�m9��1�.�?������R��s��kb������j&�N���@�1]��]��l��M�D��d�GQYcc��d`Z���fC���=x��PsAqM�{@	���I�Yv|seU��?D����f���_�� xL/���O�+����x�Kgj�=1g�=c�7bRH_��������3z��=s�I�`@�$I�'N��J��*[If�,7�XI������*fe�����sP�a���TB���O*���{t��'������&;����%-�A� ��h���kB����o�N���i�����P�����^0�(������[D����N_��IwS;���bjN������ �|���OT]�u*:��a;Y����.�k�T�i�5�gcXu�Fe?]�R�)���I4P[���&5��Z����-�>Y���"����u���S�S�]`��o�x�V��6���9c�a��)��$l���2�y���x�g��.JzG������S��W�����{Q
Z���������<��;r��g���!����]�-�^��H\���m#�7�����G���_m��3�Aj��NE�u"�+�����F����h'��M�N�aJ
��HUn}l�:�����3gDD�O���+��_IM
��n��+�`�����j����CWW
��&������!��>Q93�T�x��1<=�U�'����$���-Jz��3��t[�u��A-m�.�V������^z~�r�c_)��u-'�������U�Q��G~<���cQ�}������C:�����]X8�����L~��z�6���~>Q�.��8��oeE� �����m�A�����w
��O�3�-k����Qf�l����hs�4��D|��+��� �j/����1NM����/�;�,S/��S=�JJR�����A��K=�~���BOv�k�W���f�����������E�kBWr�����a<(x�"�rI_�sR(�>����]��}��O�4�A�\�]B��G�����$�����7RXxUA��H�)��FJ��X9�+�
d�������Q��^1f�N������:@}�m���
'8�~gN��UnWT�o�[/%9������
O�+�n�:����cU���g�X�-R��hN
��_Lo�OE�����r/	����zm�>cb?(�S�'��lf�������&�YB1�3R��<�T��>��Fn�T�*9}T���@N�8��G=
�i����H�r��t�!�:�I��)F����F�0��(��>=�5�Wy��X��{��_�yP��j�|���<�jEHl�y<��>i�]�K�+9
Fg������1}X5B���5^e!����=��u$�f�!}k�������B��Pu�+D����s��
��K��4(+-F�"���V��j�*��FQ��^������Fq��_;y���N
�N�`=�f�i (	��',�^(�TA�
��\�d�(�{�3B��J�u#�����x��B>�4N.�]�b)�
> ��\bo���'���S��������%���g> �TPn�����|N�j���2�e�e�T��1�k�p���,<�����'�14)�&�,+��kz��6vl�V0��0-�L�W��:~*������<v�.&
��r
�g��8r�����6�h9�\��c�q&�v|
�%�h����]�~�6���sF/��(��-���"�mR�=���� �l�-��Y�~�=��ET��!����'
Z�8�t�N�P�"���&���>XO��e������z�I��OY~:�����S� �v�|�Q[���"���'
���B����+��9ge^�'(�rs�1�0lNq�1-v��X���"�I�JQ�� �)���=��
�fw
���Y�u��_���o����������OaR�������a����7�J�t2��%�-�(X�WT��G���m���T�7���O�E�����W��M��:Q����a`�����m-9]��c����T�~�����!o���GjhG*��:=H���5x@D��X������l�	����H�P
������Ch��L����1��!�E���#���0�u
g����L{N��g��4�b\�v���0slG/,�ao������/����K���3�#\����R�~�g������;���&i����������@�����r��HQ�b��S�(��WyN�zx��,��t3:�����b
�}��:���T�qj�e^+�>P1qRcq�t��O�I��1i���������d��;��WYz{,]x3����U�����
��Q�}�M:�t�x[�y%����o��8�M�b��z�C!W���>�r�a�N��X��xN6�X�x$��`���ar[��&�yW���}Z�Do�H�9bR�:%�����.�F���+�34|Gl��B���4�+�^�!���t&t���c3���]���h������:�L*�=�*K��f�Z+t�#*�O�r�L�������E�	9�u"Cc�� vS	���Z�P�5[r#6�M�L���1V%�)Gv��H��j��2�Ik[Szf����2���9i�u4U����mm9M���J�������gP!K�GE>��#����T"���8�f���+�����x���6.��f@�?�-��!�[�� �����I(�(�S�5Gd�H���r��k���R��� 5�5����6
�.���	�L��gY�v����i�z����n���yxP0���n��C[����#z/?U�4�*��e)UF��q�y7����b�A�t��k�(�;"3��O[��,~��D��tx���q+�&E?����4A�4��BzI������j�iv��-%cO��+�8&g�1����q�7����=gq�~���B�tT+xV�Q��zHZ�����}Z�r*IDob�n�1�8�R�b;�s��H\[�a���%�e5X�}3��Y�g���ir��ySA�Q_��$��b?��7c�C~�G5��]��N�s�l4��<|���H�
�������k2G�{�iF�iFL�������4������c�P
���;E4���%]�����3:����cb���`b7TVbt�[��2�5����[������-9�|��g[�N%I�9}^f]1R����|Y{D�s�@'��^�[/fD�����!�r�'�����i%MY\�=�`%���${�J�����:���Vm�o�H�!)���	��:%y����P������j;��}^"�^��n[���3�.h��Y@��N��������=Lb{���-�qP �����'�l�O ���F2��F�,vD�%Mj����\
sV9����-�Q���@5���8�H�ff[)�b�>(���f����-4`�,��!����N�Mi���o7ikg	�����T��fG ���p�0r��d���$h�5�P���T#�:��+=#�%���&���4��a�y��i�X^��vm�T�|����'j�x��_*/���t��S��F;5�ql�p��z��_��W������%h+M�@1H�1��mL�����D��P����<��������XLeG�L������.����k��26'��,�V��o79���.��?/���k6�\�����tR�����:a��#��a���8�#�����,��OU��A��A�A�4�f=Mn�������9����_yp��p%acUe���JY����4�F
�3
d����`�?�����x���#�|�,����B�<m�`��;����O��(��M���{�V��rQ�������k�G�vF�cq�@K~LG�x�!>9jh<��UA�BpA<ZNF(�aa3�F=($!�����l�I�b/�r�<�v����z+Jj&u�q�R#���J�/\���G�s�g`N�_�fOs;������}��;RF�tQ����/J���A}�����f��<J�� �t1�����R���VO���_)^�s�xb��h���z�6T�r$N�P��-OMv����#��b �st�l��iNjX�gP����^��}gtI�-�.��@��YH�5���g5��\nhMeS��L��t�q��8�e'�3`R�p�x�&�V��`�p�z_u�1	���<C�I�^�7�,'9�b�KH9�8�M�sD�C�)�-,�z�s���t��f�UiL5_o����S1zQ�}��b�����=�$��2�c���T1�.�U�'����XJ|{���U�^������0EM]l�	h����M?���] 4�	���QO�D�_��_���0Dx.u�4����(_}��e8�Z�
��T�@�^�k�E)d�M�p�����t7�~�2���xn#=L��w1�D4b:�2��AD�x����������%�h6���f�@�3�>OS��/�^<�(���+����-qX���4���_���t��?��"�5������O��v����|���hR"����k�t����o>M��p�mK��� &h����o]���5���X���rK�=j���%Uj��D�2K���>]�����7�{B\�4���D���%>w�7�"R�������p�^�������
f9G��yy��&	�����T��I�A\~�������8��e���,ZT%9�����W`���L�u��+=%a�����x�Q�6�A��n>���{v����}���^{����)�$��%]D'����!�*)��<��(���i����9����f4����|G�k�'�P}G}E9��U��'=;���lW�3d������`�h������L'�k.�#������mf�#�k<C��>�5,v��T&�3�K:����s���*6�v���=.�#�j���i��i�#����b��@����;��v,���Gg�>��w5����W+-��`vY���=z���-�kd�k���z}��H��DC9�}������re.�k(�����!Y�@���C���"��:��?����� .����f*�1K�=e�1�����#���3Fm��9�-l^��������[��Ij�����Ep*�����k����p7|��1_Q�;��.fJdh3����+?��(�����u�XY�l<�6j���C����7��m�-�-�Mz�D�N^��RZ�}�\q;/"{�P���������2m��
������'�"P�YA�+��4CI�������)6�3��z��U�b���EG�1��8�thPY���n>�������z3�Q�Fs�G&��������c$����m)j����7[��z���Ogm�C�*EB���7�'�ey�m��N���N0�)�Cd��� ��)J=�y7z_����Z_c�m�8e�<i���U*
�!Ov6���Z	����"�Ntq2�A�=�f<v��tq��t���n5#��s�$��e��s��q�)��p���7e����E�/���Z-]=\�cS��������8�K��~�<�RJ
~��G�3(~U�����^H����.>� @@u�J^RC�����>�+��@��-�����HRU�v�������t���e �/u���a}<�?�����6x-M���"�������4��x�+'��]�?/�J�z�6����T���� ���y��a����a����������!,LK_�������'s"� V�@�+q�^v+=�My��@��
�������K=��[ ��DZ[}Q�)����t�U�4���{�s
�A3��cSn��������4�Ht�iB����G3�#�����J��+�M�
�i$�%44�,�XpK�>��m�������&{N]O_��T��.:��5��i�<��{��.�i�da��Jqw��"���C�h�S65���M���j�d�����*�X�� U�����P\���a>6�#��-�D������w�u�{U��y6<~�����y�&����[y^��LX��>�B0?ETg����0������F�)�N��s���F-�����W��Qp�W��45MV"N�1��(g�U��&H���dm�6S���(M	2^��A�'lB�''t|�ZA$6�����p�����q�u�f|�kh�g�W�N���2M�:�G����sMDoC����t*V>��B�XG�g�������V�(���S���@���~��*u�5���/���5o&a��/�
��o1�_8p������C���l��y���i���bY7y��x�s�_���F;�+��pJ4zxH�D�.(������V�|Mu�tG
���Pm��{	��gr1�9���=H]���q�� ��*!��C<���uH��������W99���A���ZvQ�T>}�2����JJ���6@���	�����Cw�|t���nKX�>X���#5�<�X��d:���:Y�N��~a_�em[��vw�?���ap3H�b����]����I!���c��#�%�L��QL����]���~8��v?�fv�
�\\d���n?��x�W��7�6�%*����H����:�m��C�a���#�Pj��3,����K�����D����Nzs(���DO���x�����'���9�������k�f&�����d=���0�>y�
��r�����0��,��� �SE�����(
};�t��NlV��������$��r��e�0M�i��H�[��1�s>=��-�b'��#�����f`���~����L���@5�i��c��k��\���g���7(�zk�I~U����X�O�-�d�
�:�N>�8)|�6h���u�[��.E��RB"g���0 ����+�3<#�`��oQ	w�}�Y��b����J�Asb2�^�J^�����!��&��
|�]!�[�=&�����K;���UL3������H�>(�'�L��\h<��@kVc���Wx��>�U%�^�f���	}m���r8�M/���*��Z��A����,�G����d^�M��b#f�;�JWD�����E� /3�_���~/�S��Q*��h�p�G�s����D�uz������(0��S��d��sx�Z]���&����������/n���T�u��S-/+>�{y��G�v��c�����M�T1����A�Ebu�t�g O�2j�8>�};��-'/�����N�)z�H�B�ih�A������J�U�I��������
����d?�S�R�A�5�FJ��&D�+�~	x�8�	����R�\?\HU��Y��#��K��.��%����'��w������6�y��_��aRBp�J�`�b�&�a���}���4�Qo�/��c�����5V#��1�\�U9�&�y�^sK\�E�I�M�E\�b�d������>����;�V����D���q8��*5(��p�ZDej�]�.	���dp)����)����oi���?�����Q��`)p���J��
�y��]��XZ<��-I�:�Q^���,_p@}h�I���
^��M@���?&�x�Uj���^!$�C�R?�!����P����+21�k���#���\<lS�������9t�v1��V��Vc\��z�q��,��1�7p�{�!.�����������F���I����]`�D�y=��	�������u��3�H��������r��.M�gQ���Y#8�`V��T
c��*���vN�c1f��3����6o��k�ig'_������u]<��?�4E��6��w�m��3�g�t-k��$����L~_ S	V�ZPTv������������t�CZ���2�V�7���w�q��AZ�r�PK{qB��������V�v���8-o������������i��
�E\���0%����4�4��9E;�68��/vT\I_��:](����xv�~�X���u�M�Rl��K������(:���D��3��u"�NTR�rv�6�q>���6}������2����<J�{������W���Wr�J���f m���#���,rN�?p7l��xy�'}�Y������x�#F���R,+���)�`fU��H���J�D��
<a1�m�~��Td�,o�/���#��u�C^MM�6R�U�C��Y��� �Y�;5O����w����	�b>�a*���w��������_�}�3��N�z����C����m��7s����N���s�yu�EX�\"C7�I.���]�����A.2L�Q~~�F�R��Q�����Ge;�gUX7	��t��{����q>@��=
����L �RS�w�5)����$�!�K��W�p� G"$�'APO�y���~�%�	�LM';]����j}D����7y�MK��4����;����+v����x���u�)Utl|\y�����1`�#�����oR1Vp�x�Vm�O��&
�g!���I�^Ba�!���N�Vy�������*����O�dg����T ����EH�F�v������;�L��F�o>uj���kibk]�����=��N��}��=w�Mz�A��GS6E��X�9���#����5�>���(N9=������[�N�+��k��m�u���8��d<o�q{|��&�#�'?�]g��/'������9��"�?P@p�o����������'�z���G��U�
�Q7~�������P���l[y�vU=���F9���1	��$u���H?���	j~4c0�i�(�Bm���|�N	������\����<����*�A�)��B��8�����
I��U�i�8w������jUYp ���}�8�������m}DCO������8����fL�f����R���z�����&��Z�A&�����\�	@����e������gjT	��*��*�1��q��j��Kkv5��$������y��X�mY�0L����*����j���.��-U	#��CZ9@�Q�����n��|<EO>��e�?:�������]jW��B�R%,JTk��}��ZgE� L����&�~x����)B1mZBP�d�����]�	6���$�%YE�Tb��q����M��4��r}����,`y:I �k����h ��|��X>��WXrul�W��\���o�i�1��h'~�
���Sqv4f:rr(�t}���{����$��hA��mI������;,:��DUm\��}#���Ob�9)����.+���nC&$�:�D^R���F��/��z�������Z]�a��*,T�W<p��z=�D�(5�2p8N��
���)��{����:9�������K�A��	+��'�v�=3L+��B���\p��eq�r6���
�b���1�;��$q]|���i1R�(�@���q'b�F?J�b���S������ ����TpU#�� �%��/��<
������q1��uz����^��K*V����8
p���B�K�!4X-�
B:��G����jCq�)���N�s�c{�@���g�L����'xR���s���-��w��w�9Q+u�F~���.Jg����,�O���r:j�����������/8�������2�;��z��V��[������Nmc�y��
���!A�}�m/%h~jg
��!�����v-Ox�N�WCa�V��t6�������
����g/���Q_�]�z���$Y��N�M9��F2���uL��f�%��9
\Z�XdX����]]iu��w�8��W3S�<�C���;���7l:OSE���V��<�xf1���]���.��dO�$R���`4mr�����x�SKK�Py�>#������;"wb��X�;��|6��}/�	�
"=q(��:���(w��`�!�,��9Q�6z*(cr���$(�"��+
��7X����*�����vK������	9_@n&_=^?�^~��LAp'�~��(���<�(�v_��4z�N�n��6����V=�u�>#���:D����_+Y��m�qk���B�nJ�d��:�7�g�������r�����>�_�At3#>�
�D������A0�Y1i�]�1�\��9���Y�E�PC�l���S`MT��|�{��\R�Z<o������S�'A�(�4b��2E�B.49e���c-U�<�(>K��'���e���s�t�i�G]��l�]�A�����!F�J���yJ���<g�/D.LO�M'�6����7��7�������s�J������9ck�Z������$��)n�%�j>�E�Y�	 �w�-������%�?��Q��r��3���$�����l����2oo,����H��f������J8��O������,��\���]3M����B���WVH�o7���9k�e����g���	�F��[b�Aonj*�K2;*Dw�r�Y5��u�p���2��'J#�|�|6 Z%���8b���y9�LE����9����@�>D�G��������2�8���_���9����l��!��g�'�?-&"=(IOD(��y*�z�Dv��<Y�/h%���=�_>*��.?��P�4����8��a��,���}�v��(�b��,Wwg���]{�����	!����M�5�.z����{��w`0�&J���nNA7��eya0��+�S�]��W��]j�R����0v�X��7T�k���,������3��Wx�L��'_n�`���)���de��q�Jp#b-!o�����y%���7���*O�c���+������s����y�|�R��o`<��!D�V�������|QP$��3Ne� ,���+,U�Fu	P
��)~�X��eV�~�49��\b=�euw��
��.�:q����fi~�C�����?TPj�t�Ee��W3E��&D;eCx_���M��Z�9%�[�)MaR��O#�;#��o���l~��������m�hE	�H4����f�Cq��L�P���U	�P�������|�q/KT�3������l\PAy����m�UP�����NEc�eH><����y�XR}�;��n��O���n���U$Z4�Kw�����������'"����r#��L�G���1�������+��������{���	4<}�u�P���cpc�����c��6__����[I�xCjRvP�~������cbGP��(
��%���,�N�z[&�T6{���u ��a��9��������	v�S�}1X��02�U�v���J�l&���1� �	�
��&d���H�a^�v4��`Z���d�����%T�5a�%��
]R�
/GfL���2��w�L)���r+���Go9Z�8)���0�3�����2�ZSD�
�u�{Xg�����
61�K���"����n0���X�3�{F�0
d-�����l�Ai�*�L��������P@E)=3UpM���=���
{�����K��c 
��nK�������,�wWG��:%W%�N��:OuM�j�Q��GQ��JQ8�W���������`��Z,�������e���KK�
��o���P���W�y6���`y����5e��hsTi��l��z`�Uz�����$����+R�/������$��5D��q0�g3�s��?f�a0�5����]a�dE~��5����
�[���M�Ou<��{=�\�(�-l0��bQ{���WFm_K���wA�[3@
7�C�|�u��,}M�����Z��Rb���>eZ�`����4S/�e�k[}[C�����e��Hw�3����rHpX�Zb��`
��]��o��KNt]�NRc�!%�60��!����u��8�e��g������(���F|H0����� c�����D����+��S=��b��^+gF��t
��8Ri�qk��[��L��]��-!�PC��w��V/A��u(5yVp\����Q����X����M�nK���)���0�Z"Vx;D����g+��=zTQ��]`�s�B��>+�5�J���S)v�uf���K7fwd���B�V$��'�����I����R���RLV�����7^��0���W���	W]_���~�6"L-u_� ��7>��b
K�^M�%9xp�����!_ ��w����>��>Jf�Z��j��$�����9kv����$��F
w��������(����h��o�N�����7/
�@���%L�rF�wM�j��@n��I9G���&�v�_�4|�W��A�{�i�I���!�C/� RP\a2�J������?qvc��{��]rk�<	�d�7����7��[�s3AQ�m'��_���C������q�����3���'���N"�egli��b����Z ��"��hE������H�a�x9�jj	��S
�	���{���jC���C����8�:��x��(z��;��q�D�t�*!Q"(�)��%hZ�� �����O�(j���T`��
�x'{�y=��C����MaX�N���x #�����z�X�DF��'h���g����D;H�Z��-)8�/�K^�\���{k����?��_�����b����w4w��;����6�f��Z��L����j���R����8�t�|,K�Q)��~(z�6av
�
U�$���L�&aC��QE\Wc!����J���u|��b�i\
����K�9��iRa���w�,�yv�yzo�'Y��C��&yqO`���<�mB�xb�nF���P���_��n�X#p����& ��C(F��������:��v������?�������M���!,���6e!w���=�d�����Q�)��/���*
�1�7&�L#����0i/�M������N��9X������}3w����-�&�����{�a�o
hb��V�DtR�\rt��:���(�s�/�W}�vJ� ���*�D7����kB*�c]��_�&�@8���������k� T'�l
��Q}���I�������=Y��< w���������>��"R�`V�s7g������a���5��������$� %V���Tgb�����5y��k;�����#��.���@������%�b���dRz�)�s��kvcs��#�L�8����f�=a��}b@�%h��/^5c��(X^�B���D��8���I�cvF�a���|�(_2SD)��O:�a?�w'�S���^%m�3�#������
a�3GEp��4!�Cp���������n��&�/�YF��$�FA�*X�R�35O5i8R>/�(�t��!�H���@�
�J�����_�������/{�=Mz�����x��a �4�����#cJs��������z1�X�������-����mv���,��y	�2;�X��r�I��V���oZ���U���/f<Du�������H8�:M$8#�������D����U�<l�Q�.V'�r`����!���H�E�d	x�X�9j���}�|�T���w�d����Z�a����`��}�o_X�]y=����BC2]Q�a�/�j�����NP�lX�/Oec���}DLf����b�T���s�{��_~���? *�'�
r^�GzKK��Dr��[��0�d��:��������WiH8�:#8/~T��8E����
��D8�[6�4�R����?�B�=��C�&�I^�o7h��|����a)}$>�����f�i8C�A����^!�_��/*��?1PdW>_�D?;�����3�-����ql����{����[���T��
����5��>)
!��b�^�����4����b�u
��,j�7� a}��_
�CW��/v�q�8	,�sa~�����1����?O~�QXl�	��wQ[5�m�w��
��t�Q|��#��$-F>��zv'����#���R������J�r��|� c�|I/I��[��K���m�|6�2�5�m_��u3
G��"b�~O.�(�(�G�X��E>(�d��G9A_+��K�e�J�����c(��'�Z�
������&23	.�f���Dj!E����
���c>�	t�]�J�������Z�kG�R0k������ I�Kzp�
���f=6����@V�-��zE+�&�vm��&r`-�Xs^Q�et�-��m9?�
I���� ��U�5��[��U�����R�Pq�G=����1�]�\�J�Q�D�%�U��P8
M��Sn3���	�Kn:�S%9PC8R�{�v���V�������#�������m�x�t`
�����|[�IG��d�����[_�$8IL)�^w����2�^x�]s��"��Bj���dh��k�=�i}��<��Ig�����r]F����^��+�9m�=)f�Xmx?Q���9���|�/��ja���W��0����rT����V���ZE@�GM>
���b��+���IB�r)��2ki�����e-�'DQ��pJ���tp��c!�L����RKgJa�Ql%�s[�)Ch�+`���y �����*H���~tM��W�&�(F;QzBr���k���$jpv����vC��k��-6Mj�M���J7&Lx�X��w�w1�5��������g����C�������;��6�n\��;}�����8�$���>Q#Q��e���|�b��@�8I@=��`�J:(6����sUO7��������deX�bL�������I�X��m���n!��SaB���D)�u��s����i��Jk����AK�L��4~n*}��t���G���U`���9���~���(��'Rf��Z0�.B��K���
�,���Yf���v���e��������l�q��� ���9y�{�_"�>����HB�(4f����&��nxe3����H����/�b��b���d��K���o�������I~]��c{Q|�_�
�;m����K$�J�^��'M��������[�^Es����\Z�_��C4�GJ���~���vh���0��8�9P��M������r3�SY�&�7��KR��� O���'|/�]�4t�7z�Y���n���$�Y!�P�������(2���>�z5��	�Q�u��qMGq�O��k�����1�����o�r����_��Gj�hj�6��uQ�����[3����Nnh�-ze��^=CII��Y�������I+�����/{,(DZg��|`�[��h�Vo{+����"���A*�h�`�K�v_�QYN��z#��T���}G���"�F���*�mx�>�(�����A���]�����������.��A�c+�"Bq<x�p�*�pL�!��Q�����f�q���
6�j�`���A (%�{�TX�Z����P#��^
m��C%o����l`�_c��@:
b�1���Ak�r���P���8f��s"i�*}�����e:����BMK\���//�crL�
���]4�Y����=f4����={(�i�G��C^�m�HL+��S���A��X0�jXq���\Wga@�j!�g��a�wm
��2l�
�<'R����9��bq��@�:��[��K�,�UL������7Nk��KB�����U����-���)
��yHQ��sU����1dr��/4=��p��t��pk�[�IC���Ad�qa�x�����1��w$��0n.�P&���0<���rK�QRJ�������x��� ���S�([���_
<�Z%%�Y&�M$�~V�� Y�7�&y����:�.*����D	�SG�v>�������>�d�h<5��RP�}��T����������Z��{���%`�}��4\j���x[G���r��d��\psV���.�����b����T��U��k���<�|�-����ihIWpU�@��/
R��8~�[1":x:����t1
w�S�'��d�]~R�@�E��WN���J��i�W %Ex^o�@!+s6���2�DE�tyz� ����}��`��lQ7��4M�W��v�?=_����%�����3���l������<K���7�o�'�����~>���xo�Q�j"�Os��Z�qe���a �9Wl�����7�=�"��/�6�.�(�3�/@Fe�K�7��z�*��\ Xvzn�[S!ow�c�/d� ����<���;�gt�\�8���c��w��\�����X�A�u+SC�G�b�"��J�&T$���J������s2������G�{�&�]������I�>�<xu����P0~U7�:_�F�0�� �r��-YQ�IQ"�T���x�L���
��r���&�������(����R)46D���e!��H��Y_�CG��X�4����u&�YA���f�`#�����|C�.&.��P�[����%�E���1bn�+^�_'>f�����^5��@�y�d������A��&Hk+j2���%�z����F�?�w���@�J��)e^7!\�R���������bE�~�����v��`K�t>�)NoBww��_KG���0����c���$�`8������'����m<z=#6`�el��Gq�~j�h��E��b"t`�����Q�u�d�$^&��H����3iP�'����rP�������1�2���33�E����:u(��U7��U�v�c6�KQ���5/OV���yO��_����v�!r�������!���M��i�Xw/�L�{����?L���obAJ�=�nF�w�uD�;��)����9f��On�f9!cx1��
�6T��4��m���2�����{.(.cCt����0N�ZL����kp,����l^����TP��">o(������a�����z���9IP	��c����<���i�������\�[��zs:����I�}���C�~�|�W�r�X�� ���Z��oCxg�g��H�t'q(��h�,R����Y����p��G�9�gJ��k�?��R���-��1�3:{�.H��!�3Y�G�a�3��fb�9(�l
��hq��=����	c*��h8�iv�W3L�Tit��Z�)~R�9v�w�		z+�������Xf�2����,����FG}����LT3��<x��.���f�j��oF����8�5��G���m��� ]���+��t��U�4��9��?���9��k���e~���;?�f�k
�"}b�HG�E`}]�3��C���������8�	$�����R�����r����9�s�P
����~�-�\�P���,���p�m��=�I�����1��5E�|?�=M�������q9��[E�
��%�7��b�{����287��zk��!�o(�q�����2��K����il|�����|��Fl���]�z%��v}.]:�^�eI]�s�;�H ���vj�5�����d�����
4Ei3� #�����1xc�0�E���cP���Jo'��i�M������#O���E�J�(����y���Y���bH��P��W���
�=��F�O>��GK��e��/��x1-�qS�������*;SHNJ���tbWo��/�+���Wq j{�
��'���}N~���b@�S�_������e���~���n���`������"���/����q^��M�|
��*��?b;��UfY����D��w����M���$���49gj
���y_ ��cr�J�/E-��N�g�{n\��l��:�H��r�c.�<c���1�\��8$�LW�*�����#�9���f�98'���<�b
���� �O�)�NW����t�f!�^)F%���O:����Y�s�d��v�����o�����!��;�����7�-z�N���8�8��"���H�=Q�����t8���=�$�o��Q��ye��.���:�����e}��4���X�@N�8!���m�0�
�$�9?��Iq��A�,���a�Y���$�Q�BJJ��d�`��Xi��1��q�) 9����'C��'�&�xSr<z���������9~����&B*���W��h�l���~���e����zF���+�2�<)
�tykL��!�������Q�?/0GN�!j#���a#5�"l��Os�*�)��������P�����(��/�
��y����?.$���K|���XS���Cz��r�s��X����u��bR��R}�����	C��Ny&�����c���I6�����)�D�=}��`1%�j�S��)�Hb�)T~���m����s	����p��l�_�d'�������������}���8�n���T�n�w��T�o��$>5��O����	����	�B������K��
~�k)����$2�K������U��jJ�����]���	H^��TLq���(_����E���8��b�*���t4�!�u�-
�P�}�2�]4�?1]U!�O�v5���l[R�QFFw!k��&s=���>x*Uk���fNAw�����M+��]�������	:���N4��g1I>�(�$�f��������i�!H����$�99���C�:us��e�c���u����&Qk�����@��yA�qT��6G"����S���,XR�Y���
t�������x
K��<;�I�fH����p�4Ga$�ys�
�<�� ���q�����2�\�p4B���zg��\)��.,ug�Y�r���~�=���)��a���sB��E��=Wy�i�.E:-����!H�4�X�b�]���oR�y���XB�?8���r�C�������7x������qX#d�������M4������V�����K��~���4�����W���1y���]�� G"���N���R��8�e�B�+���A��sQ�!5�����][�;�y?�\?��ej��@��_�����T9�B7B�j��F���m����-�<IQ��v�)��?����~���H���=�A�U�*���X^����	�,�s�M��9L��������/��o��|A��k}��]������$�#^�)���
K�'5�*q�	����?�O�c��*���*���7M �5�_ b����J�����P��o�e�}%�Lv�������wP�?Z�,��qnm"Tcb!���?�!E_4�VWb}d&G%�|�w��H�t�����B�	���^��1Dl�"�M�Y��d1���Da~v5������z��!X�'����~������e_�l���.Z��iX��*��]$�X����rL1`�����&&@�!*��N�Y���TS�b�l��$}�XI�=c[��6e$T��k�.��Z0SoN3����1�>�S��������cW� �\Gzm�:�=R����p�D*t�,]TWJ�8"m��B�X���}p�����am���
�t��r1�1��]�?���������/�tG������!}�qC�\�$VK����������6R$h=������!m�4Y-Az�m��E!6[��d�����N 'B�t��0�>`�� ��u�������Yz����K"��U��<"�f��6�j���ccw���0����?@��:�qr|�	SSm�e��m�H�Y�R��y������.Y�>��Wx��"� B��&�gV(q#������
�O��	������lM���!e\6��H}T�kIC:�Zcz:R�^��*�$��f���v�x	�)�l�;���.����j��3��]��A�����H�'����5A��3;�`Y����_+�A}%{{�%/� �{�����]�S��IV�J���|rI)n�u�o-�'j��vB��cI]]�!4��2��eZ�����%{�Q�����7�d��5��vV�((���aH��y#���R}��$�W�@���(3mB(�K�^�xyr�CF�������C���9	XH9$�3�mM�-�l�pt5��J|�Z��4@K9�$���;?Rz���zt�r=n(���Q^�J��o���i��!�Li����x|�|�$J2DI<����B�+�����C����X�'����9C4y���/�0�,hT�$T�Qk��Q���hF	z��6�DJ��h��r�3p{�����������`y)x �-W�t�t�/4o"8"N����(�2�V ��:�"��]b�v&��#g����9�i�����D[ !p	!�<Dc��E#T����X`����Id��P�'�2�����9�:����
�g���+�E�����L�88CP3�I��k�B��3rh��/eb��J�f8?�)0P���H������)�3��g��1���cl�N����L%g����!��4����]9�.�����J%k5-�i�[��(��x��%����/���Ybz�awH���l���������S
M���n�����R)�����VW�m�4�$b��|n�)����Mh���y4u�.�	�\�aw������wP.r�w�]"�1SCL����]*�F���l�6a����d<��\���2:�(�U��l$����F�4�:���`�(%�Dz��	��[��Q����������Ok�9�
�/��V�E����bS�������.K��}i���d\���c}Tg�Z�E���QPO��/e:�����6}xC�cgNa`9�Dr�7���Z���������i�)'�����'�?}H?�j|� 	�������s�\N�2E�I��C��ueA�@��T����1w�Y��@��d7�m	�M�v��y��,���R	���T��T��$�8D��ED@�*�����y��+L3�3��qcA����C��:����-1'QA@Ti�� �:���V�L�b��i�V�(8�������F]�]L	J���B�I>K�!��L.��Y���{�Lg��v�0����l+�G�8���������7��h�Z�wST��� �lu(��M�N%Z���M/�@��MLW�!��#���g��K����
�ywv9]��Mt�%\��"�^N�
Yv_�/}^?���WnnR��Y�W2x����!�m��<�m
�������B��W����#|#Y�v���A�8��
���=�K�
��M%����Q�b�1!i-;4�!�t�V�� �&���������N�A!@�_%����rQ3�v�)�7�Y���H�%��'��$�;dL������AN�E���������7m��F�P���*�P���P+
����o<*@{���� Y^�3)IK�T=Ua���R$��t'eK};~\��2E�����F�$�l�V��m^�w�$=�����fkR4�%�+o&m��$�m/������&)�N�����	�}����16Q!�^':��)��Dj��(�p.y��)�R�����`<_w&�������y�-�����_l*��H.K�Lu�Q���i�ZF�����X�z��n�*�x�2�z����k��<�����Z+�#���E�M�]+E���5��7��
����IR��xP��pKU����dE�B�(�t;I~/'tgZ�z�F~�q���f/2��]�0a�m�Z_�������\H��lN"PJ��I�1�v��� (��y4F��F	@���B�����Xu��F�T��w�q^��0�=�PEE^������aw��t{��R5�=�����6��e�]���i��� bZ����}+���A����!������ya�	������J�A�fu�S�
��'��~�����Y����L@���1��)�_a�����~�Ug	�H��J��osG�h$�B�0U[������o��B4�����.a�=��x���N������	����I	hEgS��S�o��4�G4gX�����5�w��R����s�I|@/��x�zfRz��SI�$�18�28��!�rA������LU�;��Xy�P��^�cn�D����1}���S���-����M�bY�AC�gX�����:
e��t$^�
��B<*�_Ns�*���]=�	����[Oti���l��D���f�}�
}�����|�'	cZ�|z�,�6�����[��C���5�����X1�]����1�I�-���4yBxeP(%���� ��2��(N%��zD@Lh��W��I�Pl��J������As��y��$�5�������a��������Ca�a��>�_i�����wpF���0���8 5d�����6��Bb����p�����n��s�8��r$,���m�)�E�jhf���U�{6G����i�8L�����a�T!�oO�C��c$Gq�Vm[E�A�nd�-FK����*  ��W-l��G4��� {=���Il�(K�������<YD��7��Y��|������8�����nD�$i�K�
���3������������sB/��9��o_������f9.
5���it��y<,EzY-E�����K�z���b-H�<�F�������^�3nJ�Z�
����%����+�L��ZY����
,�u�D�������>�Y�09n	F���D=>�Pc`g��1
�2�a�k.j��5�tS���w���$����`M�x�C{�����W���j���C!�e~��P���\�om�$3�v��.��<��=�;����������P�N�i*<�����#�CZw���9.��g�l?&�M�7���t{T��Z��w������8�`^jw�����������-C��m�$�LQ$h��`2�;/��������9�
��"��#{����C�d/�4��G���+�^��e����w�m��G��[�*�=D�'<�$Z��y����SVX��AA�������T�M�/�_����k��]�C�=?���9��������
";
$Da����Blzn��4�����1W}���J��X�B0�X���.�Z���U�#��
���5
7Y
���f��fB|���^��s{��ia�^���%3��U5d)��a�(�m�x���F��������E(��'��21��/���E�/����dR�mQV{\�����u���xks�
!�Jo/Fd��9aJD��e������Bvu�/#��9���.�LN/1���C8���l�	�b�S8�c�@�������}X�N�;�Ro�tT���,���Fcee��/,S�W�W�@A@�J!PP����8�%��`�7�������a�#�c�>��2�`y��&/���^��������N'���J���tz9&a�c���tX���mmr$e��R���)=�,B�����B�C�Y���2�c������2�n��xO7�eH���� �x�
�����^���M����������"��EfO��"����t\��m_V�"�I���Ef���<��'�|�����"�J�V��$vX�	[b�1�����%F���.^��������l�uH�MJ���)~��M�{������~J������j&�+&�r8�Gy��(^��\i'�9	�+=��������
��V�	�U�#��e�Y��7���jb�x��'���#%k����n��jk��q���#"DUy�/u����?�}���b��w��6���6[W�)�Ia4��������j7�&g����o�s�Y��@�FA��!�C���u����s����N@�G�v�Gg��63v�W
H���z����F5��H�[��?R�J�*��g��+_��1-#$��SdnMB�"z���*��.E���&���:�A�X�s�����N�W��j�y�lH��1;�����,�JR^c�u����&��]��������^IP��6����l��q+j������H�b�i�m6���q�^����E�.]�3���e�x��I�����O���'�%I?�6c��eE�
�W��.P����5�SG�l7)�*6�&�b�	�����R�M�z��[��D
�bR %`n{������e�Wga�|uq�Xg��*j����|C��hi[��������g$t�YS��U���o�LRK,�7G?�`(����������h&��r)�'Mz)�-A��z���@{����4�9�����Q_t�-��z�'�0���2	re����GaH1��@_+_������P7�%�Z����$�q�L�*����l�����"w�Mm���0�P��Xe�!�������������`',�#i>���m���"�����H�#6�c���)��V��7S�H��1��:�bi�,/c���:�5?%���H�l��eA4�"�E$�\,F��/j���F���+��&"2���B�����_=�GB�Y�$D�LB
`�DuE���	 �4R=O�z�����Jl<E.b}y����Z��F-�6*�JB-�'���g�
������Q��d�F\������������"P�������3l����J���74�u���t#�`�kZq���X��*�HT���4AuU0��=�zG��)YD`F������`|�G
,�l��X�*�9@>@l;��ew��@w*��Lu��h�(�����^�o�?o�����V��7TV(�E�t�jMc���C�6��b��`��A��8C���(3������#[��E�:���r~J�����Mz9����N��hW�Q��'��m��#��������2�x/DJ��BO�W����g�<�f����H��2�isHO����n�c��e1_m��u�{��=��Y�{���'cj~�?)�+o\�����N�4���
j�\@��+�:	a� �fknI�[���L�<��	�B2�p�P�?	�n`�b�����u�ny��@0��)Ime�A����g�;�`���1��P(��#�Z��F���/�7$'SAc
G��?8s�(w&�`����)NE!Y�?R3x��{���;0�r8���P�BU��8��D�����}I(T�7$N�������M
o�����x��
D�5��;�����v�o:'�v
M��d��&sO���J��c�y[qM�N���0Z�qhr3��sM����Oi#@�w&��R�(q1�E��pX�,����{�������I��f��"��4�=���[��z��l>�O��(D���1�S���������"`�oA&�1*jB;���G�mEG���Lk����u"t��Y�Z���I�(��@��=�G�*UBk-��z������F:f�89���:��;is\��N{f�hn���eH��,���r<-��X���2��������6�)=���8Ws�<I�*;&��S����A�F�Vi����<�1V�o�I�B�7)���a�W�����n��l��#����H����H:��K� ����R���m���^l�%w�Ro<N����b�����v����d����2�i���O���h; 8���`�}�I<����N�IyOC[<_�U�O����I ��=�f�DQP�6�1K "?�S���� �B����0)����6GM(��j"�G�I��dQ2�zH`~=�iT�Yuw�sn�H
o���4/5�d��v�����1/h�G���&[�R�G!������#O���N����G,������qi,E�=�*V`�V�
��{�sy�d�X�XO�4a+������|����[��Xk��
�~ !�u���L
j�L�a��-W�nn�apS�Ne�-,��L��T��;����dw��>n��Xv#.�����^R����M4T�����*���i
����b:������?�*,���������!�"��X6�Y��z�Y��������!m��a���g�e�e���������-Cb[�77Aj����#HN����
��6�8�J*�g`��L���Tb���x��i�0�'�z��z;�g�N�����q��r�p���$�iT�@��Y����3�]�t�)`�Y&�N��)����e��WC�i��md�B��1�l8N����o�0�:aFu]��������\>#t�#��i5���*������C�(=���&a��H�������q���|
�����Rl�9���T����*d��F@X�w
��eN 5��29�#�@�B���������0���~��@x��`�������C�����!�l�Z�^`�&���nR�Z��B���'mzO�j�Z��v�m�=��f���:��Z7Rr`�~���y�$9.����t�w#)=W6��tR�!z��m�{	\�$)[m���R��"O��N;%�����t7��z�l�-G� �N1[�K��S�����w$q��,Dz���HI��R�,tO'/�# )]d<	��X3�%�B�)V���I��k� i���lu����l��,3���*����-�#R||Yfg�K��{'��e�]�O�B�IL��H�"�
��Z�l/3�)[���O���V'ns9��lj�����5��)$�����1F"( �v)����su��;*���:�or�s�}�����?��SZu��Q����1�\kz�1�s�^�"w��{��_��
�I����!��?�Nj)�=�,n�=�I����G)�b_�Xo��p��c//=���%V�@*��%��z��d�a�=�F�'i���O'N{����.CzaJ��/��R�`I?tI�7�e3�&Yw�]���][ ������7�
��cB����y��!�wu��p�rJ������g�q�[��H���X]�����	�Q�������� ���B������"@�kW��l���9������������$�F�����;H�Dag+aIG�*-�����u�f��pz`��f�W"���A�������O�����W��ge~��e�0p��6���8�,fK�w����z���\�p�8G1��n_!�W,�P�reZ���*�L�<� 9n�i�E�Z��x�&�UT��� V����ir��u+d_����2��9�PE��
�O���4T�Ct.�R`�1��k������VE��!/z5�y���MoR�,�����~��jc)f����V���i��/FZ��^,v�;)�.D:�����b����B��j�7�9&�B$�zY��=l-�oG�v�,V�3I��%�V��2�������#����`����~��qf����n}OY�<����4\
��mUc�U��f���A�
@�eu[F�K�|����)Z�b�o�K�7�#C�e�d�8X/�s1
��������p+�'�*��#�����i�]mx)��
�'����p�0���P���2�<��,/bC�[��k>�H�_K��KG���u��J��TV2M�t��K�l^����!L ���) ���R��m�aN�3�(>B�E.�������%���F2� �C��0u&�'kst-Mn��N�g�H��u.�����H����ug���6�4�u���T\� oF�����������#�����c�q���Kn	���q��%�,1
�PwK���cqR�|AN�7�����IY����2����|5��u���.�����n�6�n|������=�M"O�E44Z-��3�Ph�u�7�A�� a|�S�_`�O)����@�4�!����3�#@`���&-��a��Z�A�<k�������f��I�������I!��d�����*��\>c#�-9>��1�d�����;�M)
�*��S/?�&�H ��GRW����G�!��a�f�A�p�h\�>O(�s����S�E|�'����J9�^o~Nhj��������r�h�Y�	c��)0L�fU*L���W%$s��4�R���HN��<P�@]��\+�����J�84�a������{��vE@�`��j�&���8K>'�u�'�����N�A!T�=�2�s���s��E�PN^���TB��]�?�+�\5�|7����c���}	����C�X�X���v�~���I��x�u�=A��7��(��,�6W�DAh>]���K��0�t�����X/�A�#	�3y�[���3��BB��5��cV@j����-m���N+��T2�i.v��c��'	��b]y��z�3hb�������������i�v��Q@"���0)d��������#����2}?�����`@�4�u��j���E��#�@��DI3���%�C�E�������SC��Q�_�@
N��`c�������v�_;�u��%`f4	~���|['Y���)J��h��B�������*�*����S�U�e�\lJ� pd����!�]?4U�i�-���([�xc&���"|@A&RnNEX�A����gm%�P=*� ��*H�i�������^��`-��N/�d�N�6��������H)[���mOu$m�Jo>o�n��]���v�tg��"����e�v��{�$�����d���I��gI);�'�����N:�G�H���1p��H�M�);���)��}��=���gvG��pX��������xZ��,��n��ve��IY���R����wK��z�n��@zYd��l��J�e���Z�n�&�d�)a|�o���Ev�����.32�I��EHb�����k1��/��N/,^�=�^��"V�����2���^v��-|��E� �yO�tJY��6��!�6��"�
��3�P����ef��`�X��^`I������ ��T�P�	S�_G���_V6���q�����C�j�
bI<FPt%?
i�����B����"L �l�e`c�	+�ni�3������Of����H�����y�`��>���,��^����L�dU� ����P0�4C������K�u�om�����2������H����5�G�
V�PQ�Oy���� �f_e$��Gb��B���/�7X��]/��)�����@75t<� :�{�e9�[H����G�D�����G]q��y�
s���=��@T���49�dE���E%�PZ���q��^���AW����������be��-b�K���v�c������R�\[-���x�3��c�bM>7�p �59l�����N�3�����9�
��-�h"�o�
.��{r?���<����	h�� �	��^��
&0�x�7r_P�������9�M	+r.���>'�����,SE�i��VKn9��8T���U
^���g�}	|a4��L,�]-�m�����V��z�n�$��BX]S�������U->b���SW��]�<�XzC��tH4�'"	T�D}�T^�����{��x�.zk��{��X�:1x�}��Gj�k�^����q�6hX��5���[U������P@2�X��="��)/��8�����XK���~S����{O#b���:>R�*�����@�%~D�C$������E<!%@`���w�V���y5::�,[������=Y@��n�i��+�^���Ze;�8�_A�(]=^CwQ S�d��n�a��3s�Sr_�B=	� c����#p>5�����?B����lRJ��	��N�7K�t��m������k���g��I(���
d�kq�'�����s�[�g���-,�2d�������K �\^Pv\O���`�Y[Bk�<���o�E��]/L���v�
�UyXq�<[�� (
��V���������?S_��Q��H�� p�����.��T����GC>����@�7-��������g��xcy���0���h
$�#(9��v��f�Rg��#�������4U
LI���S�-2nV(W��O�K�E�t��p���ezm'�4��u���z�<v��v3�_P����5�A����2�#yI��{�7M���!.���)=-� � ��h�����{��%#A�&�dM�6�"Q��J�+K���78���{�����!N`~�����*])e��l��ET�J
������w�^���%V<���Dzp���!����^w}����.�`���&���QL����q��\���VL
��w�t�R��Da�L�������zj�v4���A�\�|�
]vB��)H�������:��t��rD�AQ�2�Gtp�v�Q;)X^F���'�"����h_�������s����>-Fz�}��q��5�s(�ku�D�oLL�q�=c�"�����W�����,�-&�^'�0Is"%�4/L�<Jj�?��������`L�u�x��XS�"`fG�;���|f��V��-^��kyw��Q��H����|Ww���1o�1.�E}�KN��s_ZM��<�i����g����#�u���X�,bh����K�����](�UwZ���k���Y]�Q�+���-m*UV��!.ED�#�;
w��~����A
��N��v���My��a�������8�P�No���!���LN#�%�#�����)���Gx�e�=���U�u������bS��&DG��.S('+���]��z����}gq��r���/���|b��~�D�������]����a��K����n'���X�t-����G�@]_k���NqN>.���r���3+������r7�(�b�n�X�e>�&�����������D�`"�s��-:��Y��v��=
�����w
S=�D����v����J)������>
�uo��q�������;Ly�S�2PI��Mh������8e0�*b���kV1=�H��7�^���A�"n�w_���p����r dy+���*rq�j���y�B2�F�O��@���6��a,�v�L������ w�����}���G��,����i'.#����p�F����4�G�~j<��
'�9���)���.��I^�{�O���S���W�����i`nNs�+�?��}^�0����@���NN5��i�]��p���dJ�}��M�����Ic��;����^����
��s������R�H4(��	J��;S���p�v%g�o��	0�����%
�����y#��#��k��
������yC�K�e�� _%�.�<__�����z�}��%�Ke#V�b8G%�T+h��{���VM�%c�V��F��u_��R�����i��b��[/@��et1;�\�+6�=s���2w�����q�,���|�9��p
�L
-���������~n���$D��oX�
�lj�'�p�W�`�	����m8���by�|d���b�9p�E�����O.�!����%k�B���].*fU�����)��B#E�wg,l����V�5�������7U0����f��1,��%�j�n�Ure
:bJUp��A/�l���f����I�����p�w�����
�R�0�D����r1�,��q$��HNi�C.f/$5����M�u�	���N���gmx1f��}�n�|��Drl7�Cc�*rtk`����GbI�(X����@Bw���\�L;�������-��k���X�C���������`�6�������1�&�`��0V/� �*�h���}iD?L%`�Y<��|�E��W����2��b��H���:C�e�aJA`�����������*/H>t������y��9SZGX��\w�hCC���_#���g�T����Q8i���7�v�i��D����M�����\J�F�/�]��K�Z���Y|���\Z�������
�Z(7-�r��/�
/IS�v
H|\d������m%�8����F�S��3�V^9��XRc-���!�������f��UR[C����avo	�:�I�v�"?_�����I����������@q�|hF������g���,/8�5��$d�"�n�|�5����>��ga(<I���g�N4uDr�a�MU��}1������k��M�
H��4���Q_7p`����
Y�M�SN��1b�]4.�IQw|�����4��d�{3��������4���t��U��%EC����)��w,����o0/����o|)�A�^[u.�'�E]�(�R9�v�C{�?Y�i��+�?�����+�����o?#`�K��\P�uB_�	�:O WS�3?)1�+�Tw4k�xE�Z[_Hq�` (
xC��i��96��z�i�������o�Q���<��s)��I�tz����.K�Eu��(���u��"�Q���X-�?�vR�H�k�����UP[m���l��.a}
M����
��(S P$k������r�E����=��)^��1�����Ta�����1�G#>v��S�#*p���C��vN�5�j���L0
��Ji����4�RF�P��1�$M��B!tU����F�pt���2�H���Y�����5z�8������L�A��0��$e}[s#�X�n�q7�ea&z3�  �Ya���pl�����J�Dr���p�,����������������$py�O��
�`C�L�Y�M�_�7������/c����WF�@`c���h�n�<�c��L��R����\����+j��R0E�6Bg�8a\K��Qd�bt��C�ZR�e#6D��i���I�X�����P%��V�i�^K��7�dx`��Q��{=�G�����^Jt
C����fg�(�l2%����2f*�S^uj��2_�63�K��9��yUCQ�y�6+��%����������&B�DJ���8���Lk���"����2<�&����E�A�#�����b��m)v@d�F���� 7^kF�O�����g�u*��'J�'��Q
����hBol+��rS oX��_���|
]S�Y����|����C�+loz"/w�mw�j�i9��8��~�eOz0�@���MSl��������p��X`��%;�0C��4�dO�3 �T� J!�:�F�D�Xj�K�9�B��Bg��Z`��bn��`�m}����m������k%pnI�j����
���)l�aLK�xm1�,����	2�Sb+���g���!qb��`���\�����N�Y�!����p��	2�Y����"�"�T��%���D�:I0c#df��?����~���H����7KhC������k���F=�m��q��;����4.��_v_�/=|�y4���9l$a�!e�����D����`"��V;RR?��j�16Cz��?���	����h�� ��Ub��l?G�Rg���1��Nf�b�vY��.w�6��g��"����s'VK�����f�����,v���_z�|3�5?.DJ����3����"1�Gs'e���3)[{~����R��J:�v�p�;�`YM�I�R�����:�v��F�a���_������@���jI	[��n�w���������>������Se������FI �B��������/&�j"�;����Nr��'���h��A��<M��.��"��1Q��J�8����;��2�F�����p�#���F�PV��J�U�<��d
6�!��lj���o����C���`q��JC"d��\�����M����CS�%!�m�H4����=6F�&���K�V�@�\����H���mJP�"�d]uC4L�;L���r��J�_6[o�j-����gz�s�������QRp�kk_.$��N*c����W���J�Hs�E�-��b/�&��w��jx��{4%!@f�I���E`)�C�r�&����O���9 	&zYl	�X��mA���"3��l�y/�cj7�b^�/tc�at�.63E���V�3Y�*�@�?KKVogF��UQ+y���`0�����0nI��L���i�8����^���:�
����Y�nx9x��$j
g"��p9V�B��k����vn)�L�+��`�$V}��0�+e��i^D�C��D�*)+}�;�}�p�����M�	�������W��,&�3��]�tZ����B�teY�I��H���xz`��,��;�e�ow�-Eb��H�R��/�t���q����5?Ie���~=h��
_U��;�7����h�x?N��D�`tHnqM����=��@Y�-/��U�����PI�,����%��7���4;)�
P?~��(�2���E���y$�{���[a�K����5�"��	���]J��M{)��!d�H���X����4��;Is ����6����;b�/��3d��b�����g�TK.������ ���$������Q�����0i[n4��z8a��=:r:m���|^K����������G��<�Ba]�V$G���VlD�>��r���5-�z8t�M�%
�.����]�`���hR���A?�������o��L�n!E�t� 1��xl��:�i��@e�:d�A}�]���
Y
�x��h.������!2r�>�:�]X
2�ZR9�$��."B���71�5�����#!�E�(���/iy=����t�u$U_�^��q���D�O�����G��|G#�&��!��iM�����
b���*���>��"��[�����O�H��!/��JU��B��>�'����.��=���5��c���T�����pW��u���6�d�������m��z���T�F��}K�.����E�� u\z76+����h�����W	3`��U�-z����weZw�
�QVS-�	i���w1�
`%���\kv����:%��4P5	<
-�to����m�`.X���g�<��0����&t�m�4j��.��=�Ym�Y�,l�����)6��[?d�n���M�mt��b��d:h�O#X��{o����x,��[�Y�=�$i>��F�����5����7�U)�l����o��)�
�`�f���!mv�W�wa�af	�fo*HZ�jZ��p�#��v_.[��A$��	%���+-8D�d�I�_��	?�\=��ER9\��7�3�%���m/���4[�B��� 1�����O9���8��*�����=�+�xo���S���:9�;<�f�(�F�i����4�����y�TF
��ER���	d��&i�O$��6�������i=w*'��_�R�R�����%FoLZ�%�`�<:X�F�r9:a���P&*�$f���J����S|�����4a<�x	�<�6�����L���N6��h�i.+�F�T����%�&	]�J�3%M6ULF�P���S�h"�*�U�+����w�7��Jd�Y����?t-h��mj��6R������8h�����.�a�y$4x���.��Ng����������H�5�n&��w����v��2����8�9�����Ml�U��#�bc'W	z�@����?M����Aw$���.#���c����UC)�N�E���/�'�� ��/�HN�;�{��Uf�b1"���0"]�jz�;:�TW��
��'3@~������ckF�	4�A$6��`p�I �c_�f��#26�43��_��i��b��G���3n{@�5�o�d�����|1���X�bP=�s��"�����`f}������e���0���}41�B��6M��&���6o����~���7��R��7q6�lB�d����^(?�de�����'i���Hb������:�������������s��Q�����q��V����?� }�R��c��zS�{d	��%@��k}�+r����_���/�������G�7��]����c�0X��y,(�������A�����_�:f��C)�x�?�!Z|Eo�����p.���a��MX��0x���}�h��3��a:|Y��.OX���>���&����7�7��Z�~�����Jl�!�?Y��J��^����g���k������������v8��L�����J0h���W���f�W�l��s�rN����'���?e�����5��I�[������F��n�K���,���r����>/��M!�^*��5�c�w���M�Q	���,�*��~s���L�.����<iu�.�eve����/L|S�%h�!XF$_F������o
4�-1���i��_T-#
�����*m����C��s�<o����|�b�L���B@b!��E jTB����9����ox�h�D�i'��X]X�a�����k,U�����cD�=z�y.�rZCrs����M�N�}.�������V<��f�-�m����e?����$^qGl�?��������A
��_�z��
e�%"^A""�a�U��G%�������(*�K��8)E���A���)���E]�W��u�K���/H��L��#�����c�����;.���"\^G��9��w
�<��<ug`�
a������$��&�X�g�q<�Tb��v�7�*�@a�)���X�_|)�XI�k��3l��\���j	WCpB����^���0�c�s �,Y@W5�S��
$8y�F�V�g"�bN���h�/s��Hh��^D��re��0�\�AL��]?��A@<I�m2sF���)cqSo������l��.D�tL��Ox1;,��)�?�ug�f��:-��Q���n��C�c��JQ��^��'���^�R����d���YA���}5�T�(�yK�@�"T?���mD`�r���+z�����z���^����*8 7-�����N���(v ����x�R���Z*;d�k�s�r��BVP�p���R?	vL�� �X@�"��T]����)R���@r��$��m*��M���������/���a�����J���B�e!s�@-��N4��O�{��yE ;OP�}#�ai��2�{�7�x�E��
V�������G���2j�AA7���A���um�!D���&D��|�
B���W�1�?���yS
� Y�n�����v]Q?��^-c���X��eKb���s
�9��2m�U��^��/�@���d�,�T�	6c1�3���1rS|����+Ntt^��y�du�~�|8H`�����_����� �\2��-�;Iv�����:njX��vz��ei�.G jz$ ��
��X���������ft�+H�
�D�
�z�)�k���P������<����w�����������EH���m�$W)5�8��Y����X��e����S~J�����[O�8�)����,=����������x�)��:����?^�8��I� ����%�Lavh�B A������������ ���h�B������P�!S������
5!?���`��+�g;x�8(����E��qU���(��)�� ����-�>���y�S���,9M�\O���)d��)�������~X�t��eH{v��A��3�E�O,��o����G
�3�6��%q�m+v��"`��_��gG�j�
27&A�a���
�Ns�w,M�&��
)(h�V���E`e)�u��0[t�<�����������(�V,ay���4g<4�AB|
Y����c��i��{������sk�U��f�����_��5�A�/�5d�� ���!.V�3�����p����e^� :h�QW��wb�r?���l%RDzv$�2y��f��D��	����k6��]���~�����+��S-F�N%Vv��e@y�/��`&&Cb�{�gJh�w�F��O(�$c�]S�&�;��'�/ `l�w������=!d,�PwOw@�<����N�~
�%�B����pN��ySy�a�X�.�c�x�*y�8
&���K�w2��R�W�}�������c�NQ�����������
�&>5+��������=���{�u�nG?z�h�g6��	��6�/�����4�8�0{��o_��R�}�����
�5�	�3E0�����)AKkb��O�����-(X�^o�G��G���������+I���S��Zv�"�C'�^f3O���iP7��}"�Br��� o����e*F��l��)�����;`��Z�g�:����He�!�T+����N�eu��
��jh���u�O����h����G$��g�L�����sKr�t�������Z��`%����`
,�������V����P��ny~�n��-��������)������`N�C���h��"��K�z��0�����Ix��g��'���C[��`���M��U��t \->2�<����3&�M=(`�������DkA�����/���
z2u
cQzj�&�$b*��B�i�X i]H���������xa���>��'� �)/���>�\�.P�$��o�V��}��al�C	��\�.�b�-g
�H�x�v6C�iB,"�l�&�P������H���z�i�^D������a���U�����/�+��{�Q�e�'����[�aM�H�%�lU3�f4@ws����2X�fa\�����������a�Z�._&�O���4�������&&�Oh ����`��]k4��
���i]Z���!h\}mKM@h�%c^��i����&�
���r�Sy=x��x����f��T��e��(���8����}�j��@�T���r�ms�m�}<D��8Z`��;!��_m����6#��A��D�b���LW9 :S�/�30K���%�$��nj��L5	"�8���[CQ5vKaT]�- A��i�5���%����J�7�3F���PL��9���DH5�Q��1�Y���;9�u�"����'�!`E`@mG��ZS)�,&_�{=L������R�/Y�����WcW�zB=�@��~��>�D�K��]�=,�'���hz,\\Y}�������Q5�(/��3��v�<sx��8Q���������a��&pY�]��f��Aiw��h2��,.��:X����<�Cv�:�\��6�O������=��C���8�N��"���Z����K�����pf�����e�Sv�s)�������+���4#A��l�]���v����\�x����L����H8�w��`
+!���e�pkz�y|�Z��8���<���	�b�X{������`�]m^��9��/[��#i������t�ZVG������w���}�N�[�q����$�,+�;��nv'���'���N�����~�Q��/����������I%�,���b��-5���bo<YjS���L:���'��X����i��=����������'[�n�t�������&^�V�tY7R*�R�\`7g�[���t�o���m��2�I<KT)	*���^N�8�l��$q���_�����;�v�x������v���t��t��������2�� ��A���6�+�7�����*�5��Q�~�Yy��4)���b�������
C�X^Vg�����l����v��M4��F�����?�/u���8�d��s}E�F�'��="��1@�����yhII�-�J^�������������$��r��WR���]�-S#m�m�m��
�L��"]��S;9�+ps�8�U9n��Y�e��?ux��8m���y��`K�?��U<*�����Z6�������7����r�V����}y��i�f����0g��$��������C�s�`���[!=�Bz���������=��`Q�k�M��iH�2�o{�S���N9�rFk����H����������D��4�)��)���1hQH���c�h����C�����1���y2#�L�D?p��Pb\Bz(��`8=������7�����I���d2�DW�d�Z8{P������^D�]�Sh
��k���Y���������4���8�_q��4'@�FyR�����`�>��Of���M2cc.iOC�g�W]����N@���!��H���?n�����?o����e��i�/��J��*�����E���H?77A�6��)�D*.kzJ��]���
��?�n��y����3=�23)E���^<?���������s�p���~��Q"U�f�	���_��'��C����o����-���eU^�T=�����h���/�j$'��F���� �?��7�E*�������m�Sy���Q"=��K����6o�����6o���������XVv�H�m�r�]P<V���i���i���/7@z�{|2G���K�����G��q	V(���J�J���g8�Y�J@B?�B$�:��-�v������h<B�~��`�_�4�(��	�<��>iOg�rH�gW
�����F������B� 3��/c����������u��pD�S��38m65�T��q�v$p���@�rV�8��!���!]���B�H��}K!�m	��������v����Y�l��m�����l���~���eQpi�n#�-�e�m6�7�(���`H�z�'��=��aK���Z(�x�,�]����i�z�M�#��5����,�hY��\�KX�����}�c��*;��,U���&���Gp<z5��f<n�,|��������Y�������C4���@��C$�p�sU���|�TU���Y�����\��Q�P��s�@����Gs{ge@�6zs$q6+~KDvL��
��8_^I+|�G�����|�G���j�����_t��V>�������w�����Bp��@,��u4�d@&����co> ��X�ET~$�Y�������]����B�x
f	�B��P&6tc����_�d�vgN����t��d��ys��)��e��
$o�V���$�k����[rP �w�y��SUz�r�j�/�*��go�S�T����~�^�����K�| R�ss�_Wl^nsZ�rn���
~��Tw�r���a�vLH���?�)G�.�tH����e������_\�#}/�"j�m��f�H?�6������s�{���^�
�J�����������_4#����������m�������i{����H/��M,]n���oE����-����B���``�9�����`��,n���H�\�
���������h�d�q��J��d'Ml]���MU�@,�@P���X�^�ci�Gs��[�BLq�oF��u�h������Qm��c��m�?]���p�}���������)e1���\�R��}���"����.���9y}`H�C����"=>��Bb���a���Fz�K0�qD�����G��AZ�\��~���H?���p1R��]*A(�*�*��]��a�v�0�������{z|��M������e7������������|W��������P>�uWr�#d�$�t��D�f��.���k���@��C�l��0]������2�;Y��dN�V�';��f`�Q^=R�"��F��-M<(����n[��#����P
�<�&���?
�����r�����0`�-�����J ���Z��<,g�
��u�������b=E�1S���*�L�#���E���CY����e���=-��S���B>�k������.��.@�h4o�B��le��9z��[��E�oV���Y���Zc���%��^�z~��I.���a@J�����9���[��^�G�WgUwT��c[Z�-�����?!��:5��eO�����*Sj/H&1��'+K���g���>h��i�j���R�ZR���G��N��A	��*&X��7��n���t�Y �hi��3WIe�;�1AW�2I�Yv e>�+�
�G�P�5no��V�t7�t�+��*�GkXy?�z�2��z�b)�4��&X����z���M���u����m���
�"84ts5���i�I��[�2J!=��2J8��?V�f�vP���R,���g�WJ������.�ez*������n�!��j0Fa�����d���Z�n6��U��K������G�
��;�Tu�.Kg� �>���(����*��Wm��f�&���<����@�[�D��y�H%��.T�g��u�_.:$����TrN3�Q��(h7�g_���]�82pP�(@z�"�������#�=�-�V 	?Fzy�y+���V �7B����i�|�gz��{��c����H?�o���yJ\�0��JX��]y;����w7�v���n�����lngs���x+�{^St����}8_�\{����1�:*�p���&�Eh��L:�j�q�_K�{�_��\��7[�+-�vl��V�/���W�${dH�����u��n�P�Z��W��bE��%8,�T�.�	�Z�����7�xH=L���+�:��9��Wa� �=[V{�8Z�0�P�$�w����f6�B^B�E?�2,�����N���V.�0���0�!9)�"��Mo�O��o�)�������}k��Xp������Y���o�O���,������%���������������t���_��OMA��o���ys!"��}�U�����q�G��M{p���A�u�����B����b������_��W�La����C�F������L?|����9�����>�i�x���E���{���Q�/V��z�,�����}��z�qJV�b��?�/{[7�9�����Cq�:�����F)���H�����I>�~��M|�|T��."���8|]\O�fg�]��<=	��/�[q�|������K��?��5?d������/ ��n\��w�����$(�x����"r�%��������2��J�=�X���[��GVa�j<H���B��j�K(��g�@z����B r�$��/�"{���E������o�� �^����O��2u�%9j��D���\^���q����6����6sEb�����;���e�9K�fU�������Hr$�mae^�&�K�'��n�������>�������`��b"�@�|hR"?�Sp��}G��u���_���mD�M��zM`���`���NT�fC��.d�[�s�����(	n��1kB����19u�U�'��� �t1%�|��e*M��N}�s�0�+6��������n��F"Y�`G�z&
�b�����\��_���w�%���#�J�:\|	Hp>��>eS����iT(��+�5�"�$��Io�����J*.�Ly����uO�*Xg�+����<&�-�
	�
�F��!���O��
��7�W�^����r�I�r��������xTAu�Sr3������w���
f��%�U �f8��b�^]��PS�c�����F%���]dx�����Ih��Z��Q�c�������x!W��I~��K���D��~GW;C%&���FK�?@���(��r�1�hQ"����B� %�+��\G#���De�KV���W�v�
V��E���@���[���su�D}�����@<�q������wDE� ;]�s�����);��
�M\[�r"���*��n�9q�u����R�K%o��(�r^��������w�,�|�9�='J�P����*?�'�G���������z�����st)k�m���54s�t������_�/�)�61f�1���J}��=h���������#��[6L����w�O���)4���d^����}���
*��s������Q��0�$���#|J�#���y�:��/Li�=�"�~�9����������c��W56�R�Cvv�Y�������A)c*t��D���jV���Dbz�c�*[s��������O�}��5�2��&�`[y�9r����*?����Op<fM����wB|�k�RTO�~g|��h������	�1��������6���m<_�.��|�M$���u<�������R��)�v�������������W����x�}�����a���A�M�l[^6z�"%���/�Z�u%FhU��gx���[z%�J;��)�~��K�a���\|��������L5m���>���\��������G'K��&��Yk��R�3;�Ihn#�V���_	H�(�>	�3~P�28��8��r���E��A4�RzU���%ML�	g���3'[�8y#	����{�������'�"�(n3Q�����wM~P-������������1R]m�$�`�5t��Qu������	sF�3!z����&�%y�]1��-�����el\��T�^KG�x��m�Y��2�������,k�t7�'�):������E�#A�0�D/g��d�n�T��NKZ�A��������W7@Qy��L$G����.
	B���E��hp���������.����e����_!���o���Lh������*�����O���q4���s10D�����"�R��mhg�S�Z�d^)���m$Y�z�%�T���uI���L��G0����w��Y:��W�"�l���%o�������K�;���wS�uR�Q��)�e�B��C���l��P
KB��]��9q5���D�K_e�$�'i�JmW�4G��)��6����t�N������(�1g����2<�N ���j����b���
����e�k�OY�D�S���8��2��A�[|2�r��f����jq��(|�]p�"�)�sQ�l�G���g2A3a`Xo�����a��^��|=���s_�	n���o������o6�.O����C��
?��e.�1���f_�(`U��D������E,mAM�p�W��eb�q�il&�l��P�S���M�~�G�^�����#I�{2�����Cq��!���m\*���l�"s|
�:�m�]�S3R����'�y/�$���^�E*������)��������)��d7Z}��?�+������P��
7��js]��Jr@��T����������v��Y�EoP��;f�_������})�@����S���"�����������������5�l�h���Ck���W�
������1�9�[�Y�Nve���$<05�t���'��X�$k#��Y����[�)c���al�V�j�@Y�9��'�������q��K�!��&Xw�BaF��P��jy
�vx��G$/ L�S��"r�_y6���HMIY���5��u�]��k�)�����uM����[��4��S���U�����,��^�K����3�
��A�����:b����V�(��-�4�V]��l��g���.x,���v[+�X.�^����-�fE?��'�����;�	g�F�B$y�@������e�[[+���&W���4hjA�~�il��
����U���:������ueK�X��!�u����R��,�]�,��"FHN@���a��kn�0��P�����lc��/�]3�^�^18*��I���l�T[���)p�S��0LG^�O�,���P��'q��R��s�m3X����"g�/p�*��Twf��.������%I�n��R�,�g���7� ��Z�K����E��d�w�������E����@�<
�|��l{���ZKpT���u��!��
~��"�a�������w�xT`A�<��(y}�&U��GW-X����z���%}c�>\���?��]�%q@��9O��K"��X��9/���{�����^A����&)��B;Oz���,x��j%���#�K"�f�D�qs�A���XV�\�rn��'������Bl%�}#�gL���s�F�
cl�-����C��.�s��K�"�9���~�d�ef��WE�e�����HdJME����}%m�����x�[h�L<mm*8�)��"S������!��F�c��tz�~
�ZK����	�O���?\0B�����?����#2��8����������@�(T[�����Q��&�<����?Tf;�KG
"��"=
���:����_��e�!H;OE�
W=��/$�+u���_�=F�(J>_���9������R,v����|
N�T+=�I��%�.J�=>��m�\���WI)Uv�>$����	�j��?��1�>u��tfm�Z&W��),�.�O�}8��^�D���:�(�`�r����C������D'����2������}�rv�v��h�T��v{������x\�RI�u��x�@
~�m�m�kY]�P%�����M��g���So���,L�{�� 2X�k��u�2�{��a	��Js�w�gV�U�;��yzs�����=.v:�!�>s�Z4�$pP�������U�s*�����=�t����'�����^�jZ���w�����,��8D�?�9%�/W�)����>P�����XX�n�MV��k�#EPV7N�K�rZ�<����������4����c|s�&�����M�9y�����O���u6�`�H^��l�j��d=k��.�M��f=[�� �(�[�E�������5��m7�2��8���A�1���dz�t�7c�%��d�D�Y�V���v%��)m����X�����������yn�
�LH�,T~9��������^T�<Hj�����������0���K��wmo�o��
��������#:���x���xiS�{k�okz��p�����u�g��� �U�[��2/d�����k��PJ*�RE��[������_AjW���bP^�~��3����]a;��u#�����X��H"khM��������&���%��R�������m���6����l�|��y;�SdP+��-CP�L�13'��Wk��������W�~�pGbP�V�}���-����cY�
�&���'TP`F����M�4z�v0s�Oz�q�����������<�W����1����Z����Y|f9�O�WB	BB��eZo����`�K@���'�W�����������Ze�����8�]iE�t�����4I;��V[�i������+N��������3Fd��T��#��D�$��,�'���y@RJn�LY�E6����4����/k 1'us1G;����r���oFKc�w�xI@�P�Ho�=����k�_��-�i��8+3Z�dI(��)�.m�o�W�����9p-�)��yg.�r}}��!Z������8��T�d}��T��f�Ze��H�Wc�e��"OP!=~c�����C���d,���"���ao
�(����N����5T�=�������98���/���4n�#�'�
Q����~�+SEt���K"*��������A�z���N������IP����C�>o	�%-�bk�R�c�v��^3��������nA���WhO�������Dh���f������2�����Q��m�����2��6���|F�-��_w9l���[����[fgn_����X�%j=��
�����;�M�~�	��J|�JtJ��;�K
$���i���vG�������+��QZ���>�My�t0t�td�Q�T����t2�na���G��W�V��W��V�h����>W;Vt�'�T�|�Iv�%d��RU�O
z�	��n��#�7s��%����U{�6����W
��_�M��R��u���v���h�T��m��)J���;�L���z����a}�����,�j�07�+%�D��W����T�����U��������CM�6�2��H��*���l��B�(���R)2N(M�X!��s���ib�J#J���=O�7I���w��s`zYd��������4~qb=��j���7�U��8hVF"�5��(�_Y����F��.&�Jf�~��65��"��2c������^u����Z
_����|�W�M���/yQG�?�s�S�:��
� 	����nT��%��>�����Y	��F�~�?7�����4@���������[�dzj�E��*���
���`gY�����
�B�N��m���E����7�~��j�qH	��=�LhW�MW���!TK%F����T��Oc�"�V�k���$��*��^�D���4�m�*��e��fa�l1�V��0#�Tz	��V�u����J���a��%iO������v[]������������I�G�uV�q;����E|K��1C���}%r2_����c�[��V7������|4:���s=9xU��EuK���&�)	�p;���B�0i��P���P��B7V&�."��g�����lH������)�A�M���e���P���T6*���M�t[�\<�Bc���)���(<e
tn��@Jf*��?J�7��n�6m3����@N�:�56&�.�m	��c��Q��a�7�IT^Lv�m��+�<�3@��-Ol���B��x�'9��]�b��r�.���g��d8��DtC�z1\��|s����$�a���
�����=C����[�n�}_�xH������Q��?MzD���
��76�k�c<�6�����lu�sf��W:,�����IW@\����k�����0���
X8�<��3R�O�}��T�wQYV��4�1u�^�����Y.J��xA����N�-Uh���.��r���V��9��H�z6���t�Z����X�,p�K%��L�c@����uL�U�
�D�TF(��b�wH���^��1��qI�y���=js���g��i��&gv��u���Ot5�WT�	V���l8ogy
T�?��r/�=z��cH�N���1�x;��z|Q=�����B�������j0^�9���V��e����F��$�����.p�8��u��3V�HZ�x�@aj�#.��[�����
��<�%���e��������CD����fnd���"���s�-
�dI	�����,$���I��^�)�r�p��������R�S�m��h�
�)�OsF ��@�-������9�t:7�I$"D���/�%Ay�
>���)�<E�/����Ua�B�X|���F���)�X�D��iW��J�K4�Cz:���U���O���=���J���I���
bp����������O[�;5UM�@CdJ�������&�8��M�u�����mu��<��u��������M��6��)��:����7/�V7�(�6u�����>$��K�������C���`�����Y�n��U�]�X�
�|�������63QS���n}Z���t���{v0��8�uz����/G�X|T�@d�kxm����m3�'_+]���%�R$��4=�o��:9e�_q���oI�(a?�|-����R�~���R��<�z�'������ t��;����\m����r�X
�}~�F5��&8+�g"6EX~�5��A��J����f�x�Vg�%ilHD2��H4F�?Z�X#���g���2.��A_t���(;2�6�s��Ry�Sk
��i����# 6����������x#��[��7�P�9�X)�u�����%2W�	-�l���w}���C����l$�'�����Z=Q�>�6	��8��D�|�X�����z��:�cS$�����j��:�����O�Tz��uqz�Nz��!�F����Ryo|��1;.�����jjF���#}z��$>|`��Y�Y�����n�?Ot������N,3����C����2OL��)b�����+�N-�h\�������Xwgd��8'�>Pg���k�=������2{�v��*�W�59�@P�k���::�)�`�*��������o�5S��������(B}�4���z����w?n�W4�I[w�s^&���([�_��8��J�$|��)��~�;m�'H������&d�v�h��;�
����'��Zr{�����U;���G���j�_�h�w����$b�\��].��Fs,�<��NR:x�'i!�J�v���"�F����#��c���k��r��iwo�T�w��n�	�'������8S8>�d�	����g"%����+��4�D��'������NZ�4T������������g;)}����
=B7ml��rc=]_������sP���>h��'�i�N��*����rL<��MX��+�U_��Z�*���|��D���j���zZ�������H��������G������Y�,��MU-E�e*��j
n$�F��S����oZ>���v���r��d�q�V�������C���w���[q� R�2�\,_
cAH\M:��Cm�����R��N�)���T����Y��n�IN���&�b��<��p#6A�^6�Aj���$��`��h�I�z	�3����7��/����������]l�1�u�~o.{�X1��:�s����������OS��X���	��YRNiy4(���=�`E8��n1}q�����cC`*�i$���������.:����q�(��R	,����V}V��)SUyw�������kSSwL�;�F=�v4�w���wH~xu}<Ty�?���c��XD��7�*(jx���a,$W�ss��$S?^��>���]Of��u�����k�����i^���"�\�1���j���IF��Cazk�L�*�|�#�}2v�_v^�~�������q�/L��7�	2M���P't5m$���Z��_���L����E>���y�`;�.c�@%	�6C�)b#��9�;���S�A��OU=B%.P��4�'1�4�WIv�8�$b�~�����+}f^y:��[���X��i��6�r�i��5�M�)�rQ.:-�"W��z����^Y[�i��N*P
W-�^k�Z�4u�/��I�:K���@�#���)��XZ��p�j�����2��QCM!���sYv�Y��p�r�8
J�]�?�����A��~kVk�d�
���A'��z�����}�(��Rz��P�Oy&���<���7{��Y���M�J��
�����s���:�=�'��-��eI
����`��P~BDR���8B�Co[������	�a���T:�(&�$���w��?����,�������x ��q���
'(��Cs�<�m9qQ1��KB��BJ-2&
�u�{��>s��������L�b ���%)f�rb�(#�f�}�U��\V���(9�v��N��L�`���>�j2�i�o.W�l�l�V��@m�LjJ,Z����R����gsP*.R���N�5��e���/��,�h��J
:xY9�E{�ss��R�NY{'������Mw+�DX���H���g�ja�Q?�,]O�Z�l���@gK�������rMT���?��}�=P���b����!����s��������u���N��Vc{*�q�O�����
���GP�M!�������6�����(�0JdB~�E������.���([G���������C��l_+����W���,�:����c�i0�����UsX�t@HV&�G��#T������q�U�����-P��V3m����2���S�f$J1����x+�H�B��[/��QC6Y�h����>��K��q���*����%�����<�j�%�]�@}nn�t,�rg`��2M���
E,��i[)��41R[� �S�0U�\�o���$�3������.�������kz���onv�}�5'�w�	������D�O��b6]�x`��6�D���������	����������\
9P��y����$X�?e��k�Vi(��NS��Uj���������(/����+�+�w+abE����Q������CG{I<��j�[�M�o��|�fX?����i�z_�n(.��D�������R�?��e{���$�gn<���mp���Jm�]����K�����C�����&V�"�9P����iid�4cs��P����t��|���2�����$*M��s	z{gc�����z[w���G�6�0�����v�{���:��JR0�U�o�II=fY@��;��K���-�E�)�0��
I�������z�A)��v�����W��%�+�%6�����Srzs)��A����T_h#��#>73�X�P@7XB�1�������\j���,-�N�eR�r�:3��z�&��Em�tg3ic�W�=������v��z�+Q\sz��uz��TVE}4^����`�}�n����4�Xl*��3�IzX��>��nl
��0_�>�I�zz��G�y�h�B��A47�r5T5���������!�������*�<����� ��l�o]#d,���s����J+�w�:;��Q��v>����a��y��v�HWu�������EG�MP��@������p\[�����P|�����|�y��s�A��gU�g|�q;T-I/w��2Nmy{rI`��/Qf�8��"3�����g��w�L�����W/���2�����2�>��)�����{����k�@��I�5#�0�r����?���Ex��-��SG��!(����M��tW��u�|�������.��T
Y�������>��z�\O�A��
��.����]-(X���jP/�=��O*�����"58�H�
��3>JO�8�A����0�Vc$c����3�<���������<'�AaJ�&z�Wa�q���DGsO���P&�}�*V�N������YO�<���-�0�Ay�XR��������EC����0�js2V=�)��%��6ds3�"����B�I������K�`P�8���Y���+z��������L�S]X3�c��WE�l����]]���k�����kq	��������X��9��u6�z��iM��J���F=��5%MH����5���C�69n�K��Y{��������P���au&�Q����L�f'�����x4v�pu8%Lh���/�u���?=���D�J�R���4�����������X�f��3N2s�Q�Y_H�I0�(�K&;�D���<�b���%�/��W�^6�j���X�9��q������1��A9�7	��:���&���m��j�e������+����-R~v|�W���Q�j�y�����}
T���kDwKx9w	+�FK���Ry�6�G&���]r���+dM���I}HW��������n����w�A���h�����W���U�"]�R""���v�6'�
�Dj�-9b�H��{�g��;RTW���>&�����Jz���v[W=����B��"��l��S�g���(N���N�1/��9e��H4,�tm��f�-��d��	��Hi���m���Q�wY����B5����A�G6�s`J��0�E��%��O%T%+��B6�O���U��i�����Y�S���N%���&l&1�=v�o(,����8u���:�|�����o����uY�jN5q_�
d&��tYU)���#��Sm�a]s?�����c����2�`���l���_T�t��9����������#h"PTN����Z��a�\�a���P�W�K_t�i�������F����*
Yt,�x��oO����8Y,o������I�C�In��p��������D$�_���`��8��P�}�#T�Yr��$�s;������Z�}{P�3����[�[�F���.7���� `]}�(\'M_��8��0E?�xs�1>�5�
��oo���L���5�c��a�P�'G��	�T����@�
��-��
�a��>�Gncl��Z��.[����\^���>lK�����:���U�\6%w���k����n��C�7��������5��_K�,6�����o�i$Z�P����,��DSpQ���+��-���o���?����:Hz%=B@X��N���������"�W�B��m�)g�5�P=��p���>�Y�q(�u4g��~m��c���d��!K���+�{M��=�a�cE�6���,�N��v\�X�w�6}����BP�$E�0�6�X���v��v����(����^��i�z���r
������z*=���W������h\_��n�fU{��������Hs���Ck�KU�eG�q�|!��aj����\�)�o��=����4���t���(p*p���)8U�����3����k������D�.���k�������&���7V��P�q�7M~��3f�Tv�3T�n�;�]���tum3,�*X�n���	=�;
������k�@��oP���!ZJ:�"]!*���*���I��@C��B������Jm�Z-�+�����r���_�i0�M]Le�m0�a��om�C������
S
{�f9����Z�SG^���}~<i���v�N��iuJ���|����,\,,�x�/`���o�(��X���I���v�e~�{���e�U����������}�5/���`��Nw��^:O�#��>�7tF}cw�KB*b��V�Sj�h��������{"��;L���;(���5A.s������Wd��v���U�=��.mo~�2������ji�o���,
�/�t���,"�||��x';N=�<��=���#j�o�l��A�-�L��*��e���[������O��}�L�n�����p�qv�#1������n�����}�����:Nj	���l������yH}4P{�60/���nl~����	��X
����^������lR�n�n�F!.������p���?������)G�Z��jiB*���H������k�K�$���;wf���[	���*^�=����|� E��D
@�<v����!�����_�Q�@�3��:
.�m�~�
z��m�&�Il��!EIBqb6��I*�6���S�I?)�Y�m'��pi�d�\�eOq{ �����q<<��$:l�v��	n���w�r���;�%]��M"��.f��N�R�l���Q��.}:
*nep�IV��=�V=�+A�X>���t�JP������'��*�b���GDsDD=z'�����S���A�'@,6�v��Qe�E��(��1� ������?�E�)��Y��?���}��!�G8���Wb'��GDc���4m�7�%�i&��a�)��H"����AC�^uy�Z$����B�>H,�k��G+!�i���@��7��!��g]��P-��%����4��]�$�Q&�%�:}�zkb��ep����3x/^���CM���_��2��������W5{�hrz����VL�����E�4	���K��%v�R�J��P�']�d���.�����p���q�:N��:�X�"��9vO�sf!������m��r]�	E���;�TT�jf7��A|�j������*��-���]_�e��h'�/����'��	�f����+���>�
�����a�����J'���+���s�	�M��_Lu��"��x^D�MU,S.�4���$�|p��B�B�m������W��}�28D���3�|�>ne�0�����=��h�����&����l��dO�#���	���hu��"V���;�j���c*�v_C'�$��W����	���7�)0�~�|U�RZ3�I�5/�6���������q~j.A�J,��f�X�B$�[Isi#@O��%���!�]�����_��6x�2F$AQ�2��m>���t�S+��1��4Z�L�%z����F�F�yY�S����=�~�7M��;�S���
'�����SA$M)\l�C�.��6-�N�c�<�,���s������?���*���nF��:���N�d�7���&����x�����>O+p�������Q7B������z���CH&����������,��q��xS���N�}EW�����FzJ�)wO|� ^�N?p����^9=58F�kCTG������P��=��nI�`�����G��)�<��
B����eN�v'����������	1����0�6T��)��v�7�
':��$8���z����R"^8�"�1�pncU��O��}�?.������0�4T
C���"l��h)�!��$���8a#E�H^d �.�x����-.��C�;�Dfw2�A	W��a��0~��q)�i��P�C"Z��B�6�l-�"d}}���YSJ�&�(��<��<�~�R����uT��l7B�P	�v�{V�L���2�mM|����|�	��)=�i��vIn�����s�7�R���!w~���`�)
R���_�3��2�H��@{8���S^�Q������>.g�Z�'
��Q� U���L�����������	<l�����F���J�x���_mc-�2���/i���E�����0���kFzu��`<�"����R��ty�um��0�$v��LN��V��~n��=b�/��5����3������T��"��n��|�L4!n-"@�E�+�+F0�"��;9kY�\��g��o�����*�*�(�T���B�
���O)���#1�>/�YF�l���������m��PEf(FrF2�� M��Fk�y>���E
::P�/
D��P�8^ �a�a�����s������Hd��
��8��(���QY��*5~=���,���@�n������V�n��Rf.��5J����k�xNpOV���zt��d������C���sj�4���@m5��#��"�^���u���`J�=[;)F��.����>P��g	Ot���J�qM���}��mF����ZH)����$/��8�	/q��D���fs�V{|yx�$?j��J0\QH��##��5](B���0����yym���P[�]�%��a~1
��q��X(�WA
]`���
�6Vn���������(�D��H.��a����X�N5|<�����P��_���;M���m����N����8F�wG����GY!,8N�����gDO%
��Q����"E���G�m��^�1�(D��������1b�
%�ZP��n���4�_������D��4J����y�1��/x0�����J���(��O�[��!j0@x�)�u��wT�8�@�l��$Q���d���U��3U��B��
��4��1q�;Z
]}aCWl���9u�?��U�.C<��A�AQ}��.�f�IXT9�+��d�V�C�e�SgJ!9��x��w��`b�kV�����pOc�����C���$���M|�|�0��9(��CQ��8�����j�IA"�xS�`ryEL?�._�=��\uu�[3`�`s���(�������9�%��t-}�|9���8�s� M�k��p<����v��M�S;��F��G�b�6��e�d��&�o�v3�X�It\�Tc�U
P������1N=T��[�!?��@���6�4�I;�s��9��n�)[�j��{����Lmv�bIi������>C��]W��Sd4U �v<&,i��7	��M��������s��n�����h]��u�\��r�a�	�@������Q�
�]9+�?�3����T��^�h�"���
�S[��b� �zX9\52���wy���
K�M\������tZ�v$cVW�
l�0������9��3q��b��TC��B�l���>4����Rtn'���)�i8^������FX���H6����=�eUXm���N�dU^pO�w}��mQM��j�/�G�B���[��Y'6�8��8�0�o_�C�4��Lg^�1����fB���4����h'?��I��(���*�g���HB���%����5�8���Z�����6���G5QQGaR����C�a�1.���2e$5b��eN4�@��f�f�wt�1(,z��d�[�0����/�b;�X��"D�2`]K�q,!@~��_�������$t!@��;FQb�#�\�x�H�
?���.������}��s��!�T�6��R�����U���Y}sw�}�@!S�ZXxB������^��um�Z|�7EW<>���g�*����H+m�5���Lx��6�v���tH�?D����)���6�rN���Vf�)��h2D3��v�����U��P�������HJa�H�j�w�2�G�X�~@�b2W�(S��U�H"���a����e���}C��0�~�)X�������oi��a�;tnD������C3�c��a�pU��>Q�E��D�n���OW�Ep���KA
�D�gY������8�
8�r�L�������\Z����97���$�p��������� ��[|��������0�o9�!�Q,�*@����&�����^~"&5�
G������K3��3N�����v��)�&�����H>&�z%��3�T������9��ix�5��nrWW���"q&O8������4����Gv9 Ps�9�� � j���\
9�cb,C�L�
����sVs`�����S!vl�jF��&,�4<�A��'�VV��:_*��0�U��CN��$�U��F;@�,�Q���%c5fA�^kgEc%�1�"��@i���#��i5%��+}!��F7* k��~�s�8J +�w:R5�.�b����HH�'��1���D�-�q�7���u������-���l^��&k��Yj?�Ctsv���*����JTk$���C)X}�D�c<�2����#"X�K	�
D3���8�����WK,@#�,G�_���tY�:l�&SQyT���(Wa�UM���-���A;2����+4{^��������s(pu�Hq���"|C5��H������o	9N
������L�d�vyQ�����E�������e�{4��\$�J#/N#���(���H��$�+�G���/�C~�+L��N��G�_�lP%����<j�(	��IJ#�8�$�$����oV����oGsB]�
F���e).X�pf�TK.��_,,����F��a�h�@�/�b+����P)��_����+ \���;��8F H���a{��|<�������)s9d�/G��BB8�c��:�u,2���t�CTG`��}NbX��r�z�7xS*3����8�M	NY��o�?���t�����i�z�j�s�O��@��[e���e�!�Y#��r�$�=��\Uz�a��9GsUY���rt�q����� a���M;�[�z��e����l�l��,���w,��e^����*�z�u��D��8G�\	_ju�H���yI��bs}3pRn�����������DLm��/�"7��z��TY���K���N ��t
�S����J�0s|^����X�Z��3�G������F��Dax��0�m���1/;��J�����9�����{04��'5��t��(J����D3(���Q�8��H��U�F���(
Q�L(�����G�R�����K��=)��H��_y�XF���,%�VDQn�R���8�����"�!� ���2K���g|$�.�r��\�G�Am#r,�)F��m����Feu�?���H��t���?��j#�a����_���������N�8TU�u�A���uZt12��:��v����X�(DT��P�Q��X�w�`�Eo.*�S�_gc���O�d�T����}\jq� W����q(����<��a�5m+������#�
�J��;QR]!0R8eC�'Z��E1,��������A������f�Q�D����%P���p�9[_�{8�v�C�Q�����DZ\�D����� �|X�y���
�1��P��f�a���j1p�P�b�e�l2B�����#�o��&��s��_|u���\���"��-wJ��5������~H-�'�F���NAm�����A�&������4���?��h���z���c���M������R�\�7{V��a���O�
���9��J����K�"
���g��n,t����=��4\d,O��ll��Ua��)���?�I�8��P,H������Nk�
&�.`��:�8��7��m0L��&�I��8�b�RaM�]��8���zN�N���|��Ro�����GT(�M&X��m�����Y�
	G�i"�)3xz�>� ��� gIy����&����Fa�:
�!m��v��w,�bD4�`�H���s��h��9���(V�Ii���
M���lNS�[?����P��������*���k��^.�:�PA���3�q��H�����c5;u�{�l>�Pu�y�6y{���w���i1u~d�@�7�����������"V2�����%��}�e���`	��1������W#z��(��*���8��f�P�HF�8��a�1�BT3	�����\�Q���[w�a�,�h��(���x1��_wu�G�0�~���
]�0L:q/����`8u�����,%d��(G��8��X]�H����Mt}�a�b�&R�J�"D)(0BrG���(���:G�*(.���e����
��,���m������t*0��3��Q�1U�pny�d���J2#V�L�F(
��P��A��I��s�cXa��	��WJ����a������J�8J@e{�(D��cx	E���{�.�+P�7B�b�����jt�O�]����p~P���������}���cD�-a>$�`�L����zr�Bw�^t}���(���>?��
&���tDL4[ �Bq����������t�!�j�C�����}���ZWn���w&���8�&������p��<�k�@,o�^�����C�-�z���lmO�c �$!������DG��8�U����H��+?���j���j
����e��{�}%�rD.Q�����#�����X�������	.>g6���}�EW��
k�Mq�!�<��EW���=OH��H6lp&�dq����
0H2���NG�_��q��l���Z�
!6����
�����//L�(_�����v�u�Ths��6�P9�
`����OP2P�DO
�m��U����Q��3���g�p�
�@x��u�������P��G�����v�$F��0_��Y��A�"���,c
��[�9�..LB	�
ro�/���}������8���Je�%��?��N�
�1�?F��
��^)��D�9�C���5����)��+E�oQ�h����*�����0v����D��Lu��US�������2%(J|�"@R�J80L$�.�����0,���w]u���v�4����:�-�?=����]����.����n���bj������EG�b/#��Q��k�"�#�c~8lr&c�=G�d���zM��Oa<���s��K!a#�"��o%����D��}���HPh����4b������8F���H{����>���AQb��Hl:��@����d����nU�C��@�}��E�� ��a�"�8C�����*��k�6�J����^������Spu���Q��%Q��G�x�u�������@���jHB��W��.�����>3v��h�},u1������c�(�z�������ck��<��������E�c�03_���^M����4�++@B�`a�L9eF!��}�����Y���Q�R��
T��iq(��
o�����]��+����������c�7����X6��cM=0���#]l>CNS���*�VwHhw�������}M�Hq�/T�_���XP�g4wl��!������qb�!�f���!�j�?Fg�t# �:(X�Z��|hk�����i�2_����OY
��M��/�����T��.�RqA���	��<�~�����};�8�������	�0��d�?�B���M�k�]�m��D����0mN������}��b�#�1�o������Do����	�[������E8J�������c�^3|=;��cE������F�x����}f�PzQ�I	����?�W�Qk�xW���u��3;���������D{�yYJsu<��z�����M��A_���R�
�a/����A`-���'q����a0�95Pn���w�D��\�
�>��F�3�+���p�rt��n��]�
q��u������@a��&�������O���|(��~���_t��I�(eX��.��9�:3F���N��P��39��$�1���3�+��V�g"����jr=t���Z�������2��a�8�&��_C7��O0S;F�S�A6�.������Z�2��M[���r5���r�{�3\�i���,�CkL�	a7+������a�2
��D��Xf��:��*��Nvj4(�$��*�%P���i���P�>��_�������y����������5B]O��mv������dk���8%U_���I�����3� _�N%'�x�1a@����xfC�T�.�������6"���K���ba�q�J�����]�8}v��_O���m����Ci.��z+�,���&��0?^�-f]��ua0?�rY6N{�P�~���/gN����c�]�_ N>���`�2��=�D���@��$\C)�~���-�<7?�wm���,E��s���:-V0���k�Lm���=+���������|��7
��"��I����3�����(�	�#-����q��b���K�`�+�XU��}�r������m1����������HE�������{r8RW�f�����2o����`����UZvQ�48N�%���Nw���ZD �b�X�-w�[
 ����/�B�i s?T��PW�c�NS����7;�������l��'�=�:�L[!��e�7A�����v
VE���Z3�~t�S)8��������_�g�P��{�J%+b��h[d���Xw��7:�H
b�Mx������i�q7LS��p�;�N��+#���|��q�8���::V����i�8�Q����o���� ���'g��]�Cg���y='4��]{��h��s�������� ��>!�(���j�������
�ER�2���d�����Fq������#G Yo~^��OL��
�]}��-��������2t��5!�	�WL[��$)���w���[��k8����r���o��q���:�2]\u�B�4�
$���.?��87�r���jG�_�^wy��u����������c�S���:�E���Kb���vwn��SO���0�9u�������F"������n=�?p��z��z����&1b8m��@�'J�G���wj_So6�I���e�=Z�����X��P���b�H��]����e���@�X�~�`���q�B���z)Vv�X:�IMAj��NJ��h*Q��q�V�e1�h9�:
���8=��B�L
$PWWo�i&��%-��2�A���*������D��;����/}�/�C����l���Gb�j[��m��Qq_�La<�lN"�Y���5^
�Q�z���6i�%�4;��M���D���������%K�{W�]��S����F���3T����d0������4:*g,=L���i��o��J@���Z��CA��m��H]E����B�_��W7
����'�
�%�<�)����&xx8��F��1)�gx�0H5���iPfQ���q��'?>����Rj���M�����<����p�1i���r J}z{����7��`�h;S���\��DHk�=�����GYR@�����H���X�l�h�z��������aN�1lB�����V~�,��o&|�3@�0ZP�FH��)��[mx��;��P ������jc��?2����eA��P_A��+ks9R�gEgN!�M.$W�c�[Z��j�;=�pu�<4Sk�p��������\8rD H�H�)����t7������J����X�;�������\�lO�X��{{��{��[����L�zj��F�M�|�QF���CW�o��N"o��R��
��;��t]Bs����0�>����k-��6�L�:���-SnU$2��)/����?�()�]J7J1�9A�7G�~$=�U�n��.����'&�\ <�?��?�A�#Jp�,��u�Y����S0Pv+����"9�*�� ���-�uX����fK���j] �����bJ5��P<}��z����Iu���9"�����B�en{�K��[2^�q�"�����A!���:!e�P��b4��U���f���z
{�R��6��\�,�P�����3B^�FabA�����|��q�������1��:��N���L`�T�������T	����q(WQOj�{&��HL���lhO��Q!A#
P��I��i�s��C�f�$�-aQ%+��S1��3v�M�e\��/�s8M[2�n��8@�DCDo`�h�1�����nn�
��@����?�����D��(0��"3�c��/ELP4��d�E��PC1B�Wt��i{��H�-��P��_ ��H�j25��?��r�"t��$�1o~)7�]�D������?x��jy*��q����%.����<����!��J����EA�
�a����\�F�Sn�M��;;��JK���:g��������y� �o���d����_��/
Y8�����>����9&����M�� D�8���L��?�v�\X�,SX8��y���M 8�FH/a�������(F8�#�0���|���|<�*"��1�$Z� sA�|f�Q��}������<�R��T^AF���	�H�`�v�EtfR ��L���1g��w������a?r:�G������E��7�."���f�C�����(w�v����7��H�����WN��� Nq�:%�'��A���$�TXW
c��'S�]uA�'2�8�'�jsN���V�"�<6v��[.�1�_�����	]����-�� 4�!�{�[=%��2
�Ul�'�a��;(�����,xX���8a	DS�;���S�#��`nqs{�$oOE]>6<+o��"�m��&v���am�����<x�D-}��P�B��C���h�;d+�!^Q{<�������?��i(����B���[��=��Hq	I���Lf���}*�Z7��S'9��VC2'��j�qR���w��`'�)�G������9=��=�+���pu�0��&1��K���I�c
�cv��m�/;���|�y,�4r`����S�����(	G�6�B��q�64G����!����a����#��1�����
�������D���g��v����� �x�$�]%���XB�� %A�L��!�����:���eA��}�az;�T/�?�pK�����

�+��X��%��H��_E��j��C!��(��j��J0�p8����3oj��������kg���Z��	*�� ���
�;v&ZSa�5�I�Q�_��D�
	@Z_~��S����a"�,#�uQ���<��b����@AH�����.oSta`n���6��*g�&B@H�	��i6��x`^Z���n��y(!�aB�]^�C!J(�t�q��e��(��J����M�0�7��M48�P�X�S���0#�%%XS���M4�[V�%P��.��zu3�|�;��+���hK�����,(%�����w�DT�w[��mv�9�|'?��#����]���7	E�C��7��BQ2Q�P+al��<�x�Z��rL������C�p���8��":G���co����~K�|�>�\�0�p����f��aB����CW�xN������
���s�o����{��a�n"���=V�2N5�*����z	�*~������\����f��o[S�:.o��x�3,��(���5��~�uU���v�B�#M�����^NM`��S#������G�o
!��pg��r�A���� L�����M�p�����K��IJ�X
��+\|��b�,#/
&�����9r�g"��F���h��&���c�"l���v���}o�������v�<�q��7�%���B\���C����%1���23OM%��������Q�.���a����������da�xk�C������z����5�$�sL����4K��B���q�����u���v4{B��n
;��O�;
�!���t��XJ��(��P����3T�������^�Ea/���+�n�/��/�t#
���c�|�Q�~���'m�/��l�[��c�
���(�M�W��
�"����q~A�WQ
���v��To�;ps� .7p*So�
����1
�����S]�SS�
(�?j8��5M�������6����S������B��|����9��X�IQ�������=y;����2;-�����r�hS/������%[��kW��������
��Mb����#�	��81J�g'6Z�	�
��:����)�57�<{J�v���G;����/S���s���;�,�%�|f��9�C(\���3��SeF��I����$������Sv0!�t�;�x����@J:�n���7���u/���N����GqB*a.<��]h1�zL(�\�.X���u����������]qr�������I6�7TN�{���^9HT�HgX�FJ�p����#]D|�)k�B������.��-���4�l�=�����3w����L]���� ��)8H0�A��2g�������)�����P"8O��b}�d�� ���dv9���x9g�@g����y�j�j[:j$(l�#�C�a����=X763��=O7Xr= ����P��X�������e�	VGZ��0!^���lL��>O���U�D�d��T�T�'�����:�+�z���V�1����4�f%���&2P>��wFl���6�{�_�(w�����n�T=?����x~�k��3b�qi�0DD��0�T�f�B�/�C����P<�R<���_&U�^�^/t���l[���C=UH����y�T����eM\�c�P��������a�����q�M���>c����������K?{Y���d��q&!Bi3W�^�7��|��%�.���5�R���]����G�Hq��ek�X�9Q�4R�I��Qa��|T��<���M�ro�(HJ3�V�qBxFw\n�0���GmS���3M=��}M�$�N����:/�2��w�&g�)���G���0��D}=u�i�.��O*T�K��.~U��W$&7�bks!|d�l�?��H��0&�r"���6U�wp�n��d/��*�@�p���W�������������~�����H*�H�R��������P��V�
*�Z��e����'U�7��w.B	N�s�
��/�?�H����S�_�]���kw�3N����
_�WSx������F�����h�������8������reN:Qnm�b�q$s�yn
p}�����������E��������P���$!>�G�dm�c�60�$nnxNs���!{Vr@�h�},�xG�Cj(Xz�-�T������QuZHD�G�d3`��-��yLG~�+�>��v�W8�i��Q�	m�������g����^��(�y���t�!��P@
�:z������
2������@�:
����"A\>	���tW���}^�$�o�@��j���aw=dc[�	j{��������W�F��\xp�v%���(s]=�EH�����#��L#�l�M�P�Ix�zwt��H}<��O����	�����<����D�7%�&���G9��~�m��C�� ��E},E���$fi�V4GL���P�IxM Lt�%
��A����UEF��|<��Iu*��D"�A���~����\\��K�*�P�����W���������+�lA���k���n(L;�>�d�k
a�HMV2x����j9��]^
 ����J|=RNNt�t&j��9�7�C��~BX6E���_���~��I��G��
�9uV��-�K`��9�)x=X��N�����B���}�8;�ZO''��������n�
]K�	7Gs���nk�=q(�F�����nS� �������J�k�$�FQ�h:�`GI����Ut_+�����v���j� �x);LBi�4-�*�!1jT�������LxT(��U��GX^FWEW��D+���2��R�����h���S��B�_�wJ������Wc��@��2�2n�����0���5�`��������"�p]]8�`r��'���m/���5��{������9��C�����
�Va%��J�x���vl��e<�F�=yi��b�P��V������:�H���X����	�j�9�(+��������J X�������j|��g5Z�RZ�P�D���q�
�@X	D��[�������f��b�+�Q��v�s����v�k��-��v��P�����E�IQ�X	L��9m{zTHsk�#d��'e������kS���t�O�eQ�g��'C
�Q*��{����=1�������w���wn5*G�2.�)I�����U<�P#��}���(}C�S��F	��IP�n�^;	��R��z~P��������BJ��m��:��.�ex�	�sq�����������|�Cu,/��iC0F��R�d���yCeJAxs0L�V����EUD����
�C��FR����;����s���['	.�
DJ:�	F
�k��EA�D�D�SI@K%Y���BA�7��3yu���a�@��}��&E	���e��� L$�"\g�?�?��]�Q�F�[>�cQa�&���4J��Q��
������2���K���gX��lo��N"%��0��]lc`sy��^�%�g4�@3`B3�j1��~o���A������1��R�����T(��,%��pW�B<Y����?zfIM�1�otg�C�T��Q��^�X�Ic��Z0�8���#@&�,6E#���@����� $��S2<(�3�@$d����V\�bzr�������� �$�&1"b�01dH�������4H7�4tGw��T���)9t)EM�-������4����n.�J���P;$z+0�^n�C��*����Z�b��������(4�������bhB�
"x����H
D��U�E�}x'p�X�r,FH��J�_�������QLx�$c�i���n�p[��t�O%X�����(W�	�������t�o#b����a�w�1�E<�d?����P�����$������m
�����������
�q��3{��V�WS�1�����N���������F��i�AF���
��������:�N�.b��8��LTcv������%�J�>Nr��+�������=�������������S�P�9]U�a&���[bc�f-#!�HZn��t��{�FZ&�q�tF�
�c*:�p�������o���h<6�l���{�C{47�o��)f�@���(��(��=���8w!�U����,&{�������h�oZ
P/�����:�d)E�M\`��S�
�G��1��k�� !M�z�\�#���.�mS���`.99%�9��Bp}x�o�
�"�J��t�=��bW$$��w;�K�t����e���e8�1���)�${#r~��],i�Z������]EF�k}��`��R6�2t
�����M�C�AW�S�(B44�At����q���W����A$����_'20w�*�2&�0~�
���.��vk��z �k�Q()d��������V��4�2�.)s�-N{��L�:�I%i=u}q��sHu��"V�P�:��F��9qb����H0TTXV(8���E	s0�O�������;��\O�K}e�Fn�_��*���bM�S�E��Ja|%	Fxv���q:8N�����f�aZ�3@�����DpI������T�Ye�Q�������5�����0�������p(�N���
��(���h�@��������m���a^9���6�"�q1~qv��x �{Da��
���t:|����b�v�{��p��F��N��7�q��u�,�c)�'��Q���,ha�sI6S�8B�"���g�|��~7���|�;O���v������o�[��o���7JI������������J�����]����u�w?����_���O��t�}���K��������*����ws7L����i�|�_�����.�����/�d�������w����}���>��g�a0�����.���+���<�����f��t�~��������N���xT�2�����/en��F��XO}*k��
�����k�����^�)���.LP��\�/��_��wi^��f�?�tS��KI�h�,��u����U�����W��~��c��pq;�����N���e��P��}��-���n7+���C�������=�������cwX����n�	������]��������N���{Aw(�����[����ys��-\�NC~�v7�e���=>?�\���[s��6�*��?�W�yx\��i����u��7�o�f=z� ���K���_�������������Y����~#R�����[�i��o����m��YG��Nm7|����+����K���A�o����B�y���TR����~>9���������7���//��w��w��|w�����������v�`����������_#e#����[]F���c�m���������'������|��!��6�+�c�R���(�y��m��|;�������/��������B���$�F������{�?��������r��>>?������f+����@$�b�����*�r�\��Ey����(R�X~�*�����"f�������Y�P��{��C(O�(������$G�,�����23��}�'�����[$KX�a_�����-��R_M�fSUS��)���X��t9z��r=���wI�7���Qo�P��mjt@}�m���D�����q(>�6
���F���Ot��D��<OD��x��Ax�1���Rt�-�P���(�Q����^�a�4oA�%K�u���MI(
5n�Fi�=�=��Boo[�,�C��P���X�VY���A�w�>��������>��b��~��\=�6��Vq��}��E�xl���rsou�^��^U����_P�L��$�P�x,���#�c��,M����d`����@���������������.������y�j������l���x�z�N��;�k6�`z�
���h��t]vwa�������<���IJ�#�Y�^����7����xGu�5[��>����d6}��9���-Cl,����o�t/}�G���1�m����&��o$�":���`B����o�eT�5���<��G�m�4��K�����[br�v���������]��������4��eY�_���������
���~�yc�C.V�����e]���&?�p����}�3���3�NT��S�%��N��b�<}��0�S��wDL�	�p�)�^�m0�7�c��4��ZEW�[m�O>�?���-K~�/�R�"@������l��?�{�9�v���V������uY��!:t�p�g��H_�}�i}���
�q�q?�*�v�����t��{������K���O��%������������&(�nn>�`�{�G\�Z�?�[�yw��q��$zwG����:S
�a�w��@/#4ot���?3��(9��w��C<t�GOx�����H<���(��h�����mw8#��z��m[�6,��3���E�!����H7g�� �\�0���^��Ge���X���K�[���z�^-f ��L6 �s���|U}�-�A�h-1?��/}#���G6��L����;Pwn�H�8�����cyu�fmv������W�>����r_4���Q�H�����XO^Ff����L��N��8C�M�R���.j����>���R�d���1h��K9_5����4t��(.�n�9]����n�/l��[�Q���D?���������a3�^�t�@�^��Xx���|���{�Z�Cx1������l���������UT*���od:��K���~�t�sa�����M�}K0�n�>	���%����V��4u����W��^0�7���L8�';�H���Y@wk;"7|�����
W����������<�E�Et��R��o�5*j~��������)x����A�Zy��c)J+	o���A�����1p�}��W�|F#���Y|f��(��<�~q=#�5?n$#l������rW5~��'f�U����|!�M�}}�������*�8����8���dK=�cp#����{/���0"=�T��[��I����x�b_��"�r�Jm��J��K�!x�������w��`%U��j�^|Z6m��0�X�ZuX}������[����T��n��"��%��/��0����S�'��P����8`x,phb;8O����_�k�����LF��X��E0&��->�4+�w��zX���}/wV+�+z�����'#�p���W�n�D��1���5�d�$���[�Pj����K�=�?��G"��Y��y�3�M���/��*8u�z�Y���9���#���q�>���G�mj~w9�[k�1�����K3��b�V����p��
oC4�"]��zh�$P��j�!O0���S������@��4��e�m�G���uQ��M!��:�����l96��8s��(�e�6't!�Q�8���3��p"
�'�T.^�ZA�d�l��W�
2�	�g�WG~�aU��	���g[Og`;	�\����G����������b��j���GY�[�����zP�Yf&<���g�����L��Rf��t���������S�3!`mtK�G�o0����'J���-nS�Vs�Fj	.��3"�=|��l���)J������x�	X������4*�{����nS�n|_���YF��_��\x0�A���jqC�q�~�WW���:�_^���]O���z��|���6��f�,�����R��#�B�����P��S�f)�R��<7Q��V.
x����zM��)�)����hmH1�������{��Q[�:��_�Eq��G1�`�����Ne����$bn"�J�s>�������&B`���O'���g����G/3���jz�X����]��������B,�bQF��:�rb�	�� ;uR�*��I�%=������s��G>J5:���N�tg��96���mu|:��t�V������S��j�(����=�~�F��z3?����K���AI��,��RQwR�jN��('���e8�z�`���4?^0T�����2��T��|�������U�Io�(��-�V��T����{���(>��:�K`������f���gi�c����0���Q|�����^18��`�J��h��H��Z��G�Q�y(������M���y(�Q/���P��?�
G�2�v��-�.Qx���h_�]��v�	{�v�u��E��:��X{��qh~K��U��U��������>�c`�`sc�����_7����e����Q�iW�{��S�e���.s�����Pd����<���]�_}�:�����-H�X��1:�����C1)bu��1U��^�1[�t;Lk5������i1w�Nu6�����>�;�W�r�R�f���L��4�b�f�`R[_+s����S�qhp�����9U�C��j�y�<
e&C�u����1��i�N9��D��$B������������YN�-����E�W`����5��V��l����������c�c�����
qh��V���H�[>e��th\���0�i�x��(��l[b���o4����(�`�����Gv�g��{��NI[)��j=��h�"(3��B��n5�������p�_��SD_E����=1��?cDyU��Q;T�a������^Y}>�J.[<�z��:
�M,�uQ�K��nU�	���
��Jq\�5��g�s�P��}F=��FB�ic��q!=��-��W\K�:�J�b*����I�/m��# Q��.?���Ay����������x���J��K��/j��ig�������'�C�	�q���Q6�g3)�`���$By��n[>�r�$$�_QJ��y�*���!-t�K�:����%9��b�A}���?��14����1���Q�����G� P��>�f8`�� >���9��U��������W�4K���V�94#9�L#�F����+w��5Q���<��a�j�~?^}��<H��~_�o�7�D������8l�"�Q3a$����YT7�^�������L�����X�^1������9�oC��^Kp��z�4	x�dq�b�l����=K_���`��l0�����hT�d�6�������p�T������NE�1��}�5�:��x��#$?�������b�P'�4��;ez����l.�������8�T�N�����B�
�S�g�A���}���:���S��N�P�*8��
~F?�Z�b0�,�4�f���'�W��0��r�$L:���RH��[�D3(����%X�b�Xt�%����,	���I���D��m0������L�q%J���<�������X�#^(��Nf��jun~��U7��uV��*�Y����pxNul����0ayi���_� 
*F�l
������6�������k�TM
��u�q�K%y��\�Ib�5����8�O����Y����@�-u�j�c�Eg(�&|2��up��R�����_��7f���������U)�M���y(�b���`M]�Qs����10	$��n�N�����R��_3��/�������>�'�S_a��y!�A����H�	����?���h�<�:6���B�3j*����&3
�p&��y����P�#���R:��24A�x��Cw�R���Yd�S�}�����u���
��G���aj�5�{�S����i��Vq�h�f�"�nTG�x�@�M�
�=���5TX> vM�8y`%�0Kp��K��4	�b)��/_UtV�}"v��LTF[�[�����G���1�+!_A�Z���������L~��S_��a
]X\?�mgV�9�����i3�$�[6v��-��\��M���h-����b��������9�E�w���������C��8/}���x���)�,���,(c����Yj_�Q.��K(v��gLP�Qyg�,���x�u����9��]RzY�R��o��.�RY��j������_)����l
�O�9��3��bT��l���{�Tg�F�������r6r���T��,��5K�0��ep[��m�?ziv��0L���m��p���h���%N��B����$D�t��%�7�{@:���sg�
�Ok
��I��<��*`6JsJc���$�w�w��;,,����u
�DV�y��f5��*��O�k�_�`��A�N�t77$��`&��ME������a:�c��A�Ex��z�$�S���sk�#����WcJ�s��^4<�����;0Q���`�g��zH���H+��B$}��cz5&�g3
Yk�N`
�6���I�%��eHp��<��������j��3��',���b�G�	|�����/��'�zX�@[�k��=�v3�5������Q=n�lP�:`|J��"�X�C�.+��|S���)��#�Z/D8v������uW�W	��P�Wm�x.�8S�?��o�b�>�����J������lFv�[U����I�QC�P0�-�<�����{N���H���|���eR�!���SCGHh8��X{�x��V��|{�%�$IVn�>'�]�m���LnM��Y�����y;�oa�o�C��^���DF����75��>C^z=�If�D9'�or���������?�M ZF��$���f���a�*�z�X%(boKT��F�����i�i����6=�`0:�d��UYa���=�-����Af�����+���;����Q������s:�x2���D�\o���s��~
�_O�9.��t�{h����.�v\3��e
���NyV�s��@f	���or�	�{l��s�*�C��Q*+�q�+1�3R�D���d��S�� ���1���6���p�����[��}��x~.��0?[hB+��akyM��C%a��T�x���{ o"w�-CR'�1����������<�(U~���[�{`�}X��~�������~�X���?��u��7a�(��y��N`�b��:����SX�=e "��BG`]�GK��1������Hj���`�]��������u�+����F����k���4v���#�gf��_�Fp��T�������](��4��?<3.|������.�Fy[2�%�l)�0=���L�mm�d!����8�3��7\��������������9��#�*�W��e���P�@R�u�
�DXDG���WSEc�>�8~��D������t#QAu
^�)1��2�/C�F�P��A���X��M�@�
�,�SMN���=#��a�J�%>�.������{�>[
�)������#�I�N�#������T���dY�H���d�I�8��n�#�}T	9�!
�;�w��P�,{����e�T�{o�g�<]] �������x&�.pQ�dS�C��u��F2|.����_C%B|�������QA���p���|���9��T1�L�s[W�*R�gt�Rp�K�H-A�;��	4�J��Dt,��[���;��Hm����@����'���>����F��5,l�/	�E��#L�)�Z��F�35>9=�q��>|c�8�9�`x$-O%���`Z�����(�v�
��!�&v��E��$.c���bq5���iTO��5�z����� ���7>(G5`/j�gX8?Q��n&8N0��"��p�|������m�+d8<�C�}#9��n���2���Y����{��!2���l�<�F���-7J�B���a��]���������=��+�$M�Zd�QOQ����[�%������*�4��W��^@���������Todk=�9�:8�/Le�Uo�� ��:���P����J���2�1�s=G����Dk�@A#z��
�	&]��)������+�u�}<<^	��9�a��Q�XQ"B�jz�T��'@�V��c�������8�VR�x����,�]���XO����^h�E�u�tz��p����>���o�w9��R|�	(�����i���%W�{y���|BM��A�K������cc��7I�&g�2�.��f��q����$d�m��l�a5)��r�������_����|8��LS���QA6���[�H����������;�����������#�^���	��`N7]����Sd�mj�
^�,�y��l<d��'�6��O1�G9q�U�&:���d0���vb%��U��[4;�~��k�M�P9�O;��x�b�����y�����(��Ri�b����CX��Q�o�B���>�h^e_��w�]��^�������m������p���JF��4OU�	C��?���Oyg��r�rp�G�
�zG�0�e�K2b5�g���[�j���1��>"N��9T���!�5�S�T�y%e�Q�4����(N`Q!�����2��[8),wGg�?C�b_Q�����;��r����a!NF]I�}]4�`���@�h)t�K�6��y(:N	��"����ap�L4��S[,�sq��;��\-��Pj�+�c��w6F����y]u�����T��>�����s��BT�K�*3�%���*����m�}��{�;�����}yu@� L��"�p�aK��6���^&C�%�����n���R<)�>�uzC)�������KQK�^D952��������+:��Et�IV��!27��9��V!]��:f�G��[TW�!g%qW�:�<����t�K�L���ep�V���a�a��`
��cmM�
���h(�
�m��'g��<��S�QA�"�2�8�-�<|������K���?���
�Pf�3��#��
�(���1s���E�L3�gk��S�H�����������Dy*:���'#���YJG �u����1�rn���	p;^q���U�����2�uv�b�Ul��	���^Q�r(�J��
1#
��$+F�_����@���+��,���,�����MN�C���!�"���k^�i
�}�Yuj�����3��w'2��(mlz�P��'E�\�-%n6��@76EH'�_�[��C���m1MLt�lSY^�n�6��y�Fjb���[�]�"��}R'1�1�P��\me���~k�^�y�[�'�v@��q�$>]F
O��<����3b�P�1��#��|wK*=W�G���������l����,m�N�CT��"������[(��w�*?>���?����>���[�x�!�y*��B�_!��6��!v�_��o�kCM��eq?����r��qZi�>��!��C4r��c�0�����t�6JP`���?��
���_�.k��p#���a�L�K} ����`�	��[P�����1�����2�GZ�&�M���@�T��uo��8��S;+O�P�$Ra��p����$�wLO��|�o�G���
���H�Z���An��|���u+#��2����Qw��AltW�E���������k1�M�"��Uz�����i'n�c,��3�i�Rt�G)w�>j��.��'�&�-dL�j�&����h������l�C���3!&��ckLZ&�1�]7������)Ha���A�5JV���<d����z�t}�x8���=������������C$�"nT�lQ���f+����Jk�j���!v��o�8�p��c��f7Tm�,�S�L4I<��qk�Y}3��'��N�|��vM�~L2J�%��L>A�%:�	fy���9��(G@OO��<�4�fMS������G�I�D�y|�;���T�	2q��9���;9�I���fASGBF�X����:��(\�W�����������C�w�������j������\Hr����E��Muk+���C\@�����F�q�R����Q�������_����s�=U,�?�gA&���=��"�:���^I���(���R� ��������&�������N����:C�:���}��n�M=-R�%��*O$8�a�9��T��Eh)� F���N���KRx�G�%�w��&�B��~G�����~:��n�������8��^yp��6�+�����l��0t��z���;4\G���L��
��Wt/���I/�������J,�;�8����	�=wi���Sz��w��T��d���B�?��OU��!ky0�������}��y�o��OI]�j�8�����j�������T=��cI������"l(7!�y��g����z�k9m��J6�deR�4��'�C�Z�����jD���z�N�����^w�@�������bZQejT<��q�Q��C�B�i���Y:(D�%!��a!�wpLV��>�����L��4E����i��m ���U��ql���"�4I�Q'!A��j�J:��<�Fv���q]�aD��t�;x��1H���O�����i	N�x����9���m�S��9e)�����@�Q[����4�fbP��&��������m�I�x���I�t����\��b��)'wx���Y�0����u�z�q�Cf����3�Y�M)c��R?�(���O&T�����u=@������'�V$�i1R���p��6�����K��h��������	��K�rN��_�����l`�v�t4�����O���E��,s��w�;�*�j�/���2|m�b	��8�q\6��Z���\-��bKw���i�<w]1�XONh|R�Q��NBg;ue��lXA=�R�����'F/4���@�#��E��2R`t�S��9���Wp6Y�_��A�!;���XP9�3��J���qHs�$,����6DT����������<�g�1�~[���.���%N(�LY�b\"|��������H
@��A(G���(�0��e��,
�������D���}��Y�9�(��Ct�Z��H#]�
�A�gr�:�K�5��`�0F0�z3IIwG���^Ei���+G�Q:����o6L�D��G�F;���+�1�d�I���q�m� (�����dHno�7ed���LJ%<�E}���
��I�Z�k��H�"��}�6)��Xh��q�(&��
�0�Jka� ��8�Ej��0z��F��?<:9���Z��P��~��Z���M�d��u��QP����HA�-��;9|�����{s)1]=�����A�J-F����N���M�����<j�������f��C#�V�	�<3Z�P���	���T<�'�w�Z]�#�e�C��4,n�2k�Ce��Kp�}���\�K.���������fi.�\[���i�s!3'�����u/���b��W�m�E'�Z����
AQ5z�N��kE�E
���xwz���J�e�aIN�#������3�`�~a����Z���	���+���S��@=$��Tk�AgmLL�b(�n(M�,yx|nj�r��Y�	2��U���q]�5��E���2{y���L��}���uY�8��1�:j����==����0��`tu�o���Q���FHQ�BQiU�' ,�vR'�T�7��������\�0�f��*o��K�>I	:�;���{�{u��Lp�eP��41����A��[�Y@~	q�x���������\�'�\�@���M_������d9=
F"���>?���#;����0�$���&�&��Z�����Kc����D���z��Gm3a�fL�`�`RO>�Q���n��PA������t/g/T@�(�1�!(�'����M^��8�ss�z�����;
�*���GM[�uR�3+��EQ|�g���xC��fMER/�{���s/!I�Z���4��)��e���S��3P�R�t{�����d*�A!��v/\2�"t��8z��-!�c~�q�|�f��v@\�Y�I!&A�����;y���w�|�>+�����h�NK~�%��,Z�t>t�S8��u��EY�C���[���4!4�����00�&ZXt���`@�������eL*��R���3���3m��Y8#�}�e$p���I�3�X����f��eu����F��i�,��ld@����>k�~�9�
��b+�������������&�Lp���$)���wq[TLi�����Bl��1��9S�T���?E}@�'_�Oz������������s�DdR�>�	Q��T����H�S�6������7|-f�%
x��
�M�S�6�Vr2��$
S�`�G9�r1�[��J��m#�ax�B �t�mdaFh�%�-;�0@��h����?@}�.�dT�����l�o?����7}�����G)��x�_|Q���4e�I�t6��u��w��Q$*�hj0c�+/�{�=�[��v��<�������G����\�u��I�>�)8ru�UogH�>��F��_�F��n�$`������8/d��"��&�����f;��/g��?:`B�*h"����� &��V^<o���B
�*o�fyh�0{P>����dj�b��� ���f^N_�����Td���#YHG8� ��~��?�����"�_<�M'=��T�������(2�39q��-����\��;�
�.&F���2|�!N�g+����l�g(�������1jG�M_���������O�����*BC&���N�B��'k�E�Q��9�+��D�����Pv��(
���0�����c�DLC&��A�M��D��'�����8�I�S���Z�@��R����� ?����|����G�������g��U��-s�#mj��'z
�B�G�4��]�{A%���i�DP��{� j&�=@K�w;�`�x��+�e���1�>e%�2az��i��L_���CUF�rG�B��V&j]X�x�u�M*v+�w!��`�S��b�6eS����5D� ����e�#J���%�W.��u���T���m��F�����x������GoN����}�[��Z0#��:��=�k#�� E��a38x,���6�)`�6gT ����2�q�K_��*�[���~MDj��_�p;����B<Pf043`v�Y����Ub
�m��J�t�K���_WR�]�h��R|*����s����;��=3�c�f@���������'��p;B���jf�]�	$)N(�`N�H�"��������)�)+��0�} ��!B��K0��[��T�2�6��N;x!S�/J�}��N$PB�70���\G]QK�6�g��7
�$4�'z}�
���� #K�XY������M��,�����u�G������o�C�v�S9���X�n����A�76��l>J�vS�mZ�m|�z��x����>�����}���7>F(;d;
�9<J��Zd&�H���� R<���Pi
��2��G+�cGI
�k,�I�70T�������:��p<q�2���a�=F�"?��d��"�aWk;��B0�Bv��=.�v@���L��_
�y��8����5�A3��c��ZY}�O�q_^��O��y1T'U8��Y��?P1�o�8u��Amm�!

M�[:Zt����Q"�N|���0n�]:�e�;�����2��|�I	D�z�������=��T���%�����B�(��]�pB�1q���IB[��4�����$I�^|b����C9��Z�Z�F/���������${XM0QqM����_��z���H[F��V~����@qK, ��t��7�4����1������$�rz����"0�Q�N5s���Y ������'^�u.X���s���,�
�[w sAo}b:�f�B����*�%�U�����.aC����b�SD��_
2<�����b�ml����z�).���]���8Y���X��ca���oQ�x���	6W�C��\x�(�~I�� t�m�7_�u�Y���X�J,�Z���� �9&�s�U���K�z[ja,�.��C�b�����c1�`��U)�P�m\fr!{��Mx�
��-!}����PP�\�m�L������lsj�Xz�&q
*����O�C+^�T&�����{�A=>�� ��_�������;�C�\�`��%V�g�>�X��?&J��={o�*L,|��M�����h1�\��gG0p[�i>���a�N�!���s�>+�q�&0�x����L��:�H�V�n�Q������{"Mc|S_�����%�*��f:++�~�Od������21���H��!������Y�cH��h�bL
HN�y-�!�u�x�!�'��1����
�tD1F��+�'�e�����Fc���.C�Pz����Cj�I��(�C��s]H��8���o�T��O\���1������:�����q:v��������	��39S9���9E�z�L��j8�;L|?X6J��H��B��J6�h��|9�
3u+���m�`��"c*���[����t|S��������>���������L��[��K�~v7������Gl~	S�Q����f2����zQ�N���8��ry�K2��Gw'�9
;�;l�Ysp�)&�kq#��V���+�xv���@�@�E����H�����)`@�E�
�a�_��:�T�\���N�)����������)�/n3=/XCt�J���C>����lg^\��R�B+a��86=p���*4'�_qc� d-j/��rdD]YsPe
��P��
#C��L�x�_��eT�E=Ue�q���Osb5e����X>:���:�[\�5�����������t���uP6]�W��yu�F������$c����}� �b�(2z�fJ�OA�z���$����	����#��I�����7����>[���O�	��!��n^��u�A=:'�����}����Yob#�eEpvi Q�-��>����(D\{: �	��2C���t���D�M�{,_Q����B9$J/����=6���t��J!�Q����[��l�!��STI�Q��JoMM������j'���s��{\�v����e��v��
h=�T��������>>���������>/�xx�����]^����f��^�bA�������\S��\���R|]Q�5q�!UC;/�P�91���V����������OOs�_�BG�������E�ji���\��qZ���3������������P�\|�����_��\:_m�n������\����bc,:��r�(����LR_��H�^ ,J�wu� nH�L� ����2C+������X�W*�^K���\}Et�I��B�uu���4��I���`v(�1&`�@�v (xx1����t)?y'�l]�ZAv&�{�=����Ocv�@
����5,���[%F{�p������Q���A���G�r�1��Q���2���m���_?�_�c��T��������x-�D���?+���8���n��:SF��E+��[j�L9t�������d��i����o����>1�n��C���FS!��������@*�o���y	����D�L���?!�i�H�\
��\*�(��&����N4#)�8��v(�����d*�a���z�������z�'E��r�L��u_<d3�������O���!�����N��a���t�M�H:��.�/�U����������tR����Oh�(u�J�[e��b
�*R�d�R��Y(y����i'������V�Md)���0�M}t�i��9���L,����i���V:kK)���y�����W3���=��!&�F�?����������A�(l����#�X����me��c|<<?���v�����y����M=�^u�r`
H�!@�>��r���s��?�^?%A@�;���]T�!������:&�A�&��3�XJ���o��*:�s��	�{G��Oqr|<>-Wr������V�yC������r�����8([�h������.�;1��k�
ap�n�����d��:0�S'���~�Qv[���y$\���f��+!�+��A��L�:.����g��0���1����,1���
Zw�/�:$`qtz��j�"L�~�����n\\��Z8��\G��]EZ�6�fT�6z�56iA2�k��>�4c�Prn����sV����m���0�t��T��[��`.�`"l�B�J��Y}D�j�
���\��7Ww�W�e�7{�><��\B������������j�B��"�<���r�3oT�$1p��|t���uYaP2
J"�;��C����`�������6��������@�������z��9�z�(��[�l��Hgy�������!}�����m��>��*�����2���4=��gm�w����[
�u����
D�Aw��j�0����o(��K����_��m�}�	��1��`�����|�h��\d_ �5=�1v�Ln2�td�������x���)�B�e)C2�7�Y�t����$������f����H��:���.�0��(���jx�A�
�baD���5��.��)=���20�?@��Kz�x���
�������6��P�����!��G�{�hk0���C����|��y&K��?�������S��n��=���s��@�-CJ���z�l���xXz�@� �gs�����<2����?������:�y�m�%by�T�k���6x�q���D5�c��i�w�x@���=���m�WB4C�#=��i��p��Q���K9�l��`m�� �@�\.��a�~�A�S��,~Vf�cr�����&����7
+�}<^�tH�e���P@)��f5��`�\�����(��2*�(���
8P~���<1%M��c��f�>�����	�Q[�����C��%d"�,�2S7�v��0������('+E�i2�������������d�"�=����������@�����xw�]=X�>��$mr{��**&4�*�?o]7,l1g���������M�Y���I���t������9���3�_+c@�kR��*���d`�[i�^G����0o��"���������,�A������E'DqSW��-��	���I���1(~a7:��������!��9z�@�Tt�ZR�@��V��Mm��L��3.���1������J��f���HcC>
�z ��O��;p��W��Z30�8��	��f��]���� r�y��]��B��=S��%���z��3����&k��9N�3����p,�E"�Z�O��@N<"����/����7����P��*�
M���ivN`=<�]J?������C"6P|�w��>J����q�wts����@��+
&1�C��=�����w����u�M
�<\�t{x^Ip	���V���@���>���&;<nmf��u�<I�P.2.c����FS��{�����RV�J������R�u�����{��L�.���A�Q���bF4[�V�I�*��+��0��^.�)K������I�tt��3K>������|yy���bHMI��c� ���5=����B(wr��a1�l��88�YfYN�e�A^������A��\�d��@����hH�Q����+��?>0������1/vQ�+��^������D|�� �cX
Gp1N���kdl��v�e��
�>�L�d�
��N�2�B,������[����p�oC�����m q����b9��6�������jc�-~GB�����:��nZ��
������>���L���E��F�����!w��Z�t$kk�y���tR�*k-s$����i{;?�/���i8I/���pP���t�K���g�J�%B:l�6;bXP�C&]��]���u�/)Q�CGY����n�t^`�k��-I�	s] �1�Yt(�����I�mGt<�Aex;�Y�WR�G�k}Cs�E�i�yP���0q��DlyHN�>�<U�[
�y����HZX@�2:�5��z���|}b�,4TG�v��l�#2
6��u�Rh$�~e2�tc�m�&�m���Oy0�������1f����P^���� S�L��H�-/n����|7����3%���+�=cl0����i���>���@5�Cx�nL>��u>(�u����������:����6{|z<><>=]?&��2����r��e���O���N���X�j_����n�K9oF������L(�#��]���SS8���c�)d����a
�����6��8���GA�""��2��B����aF���|��f���T�����7\e�����V�Q����j��kR�HrX�g�CuH�.�-���U|+f��q�H�U�v��k+�:���*@?�5-�(�>��J��zHi=�qq�B�w ��A��l
`@��~-��+���Q�_Y�Jz#��xk���n�w�E����5�L����VX�L�zZ���x�+��R����
Q����rt�_U����,uT'FBG�`���I#I���;!PSV�E\����r��w���][�sx���)��
��T��%�p��L���<(CA�w��n����!� )U�O_7( :i���Y�z��#Im+����"��v��L��>���p4��6����N0d>���}g�������2D��`���,e��0`�_�H���
�!��e��k�~lK�pvJP��	mW�k8e2��Q�Q��~=��	g�a\<A�&���f��w��Vx,�)LB�p�'��Jl��X ��W�oG��<�2�����c�� ^%��R1\njp���c!�)}K����o����[����Be i
r��	JA@Bx���+_x#�-��<5����-j�,��m�7�8��8�r[2�u-��2�Z�U>���S�f��b5 �����/��(�DO���r���e�C+��Z��"�T4e�����`�B����!;���X�oq+}�s<��,h������Qq���%{�BY��3.1)f��q��9.�Ni@��������A�#;��\
�N�~kt"e+C����B/�C�6�#������;�5���<�hj2�
�I�XMQ���	����Qo=���P�[�z-PPG� `T�	FM�\�;��4o5��������
������6�����p���H��uq��@3����) T�*���{HGQ�r���<��c�bTW�~�a�L��o$z-����Pv��|9~��~�_�]��V�����z�@"PR�`�Lo!�V�W�� �jA���������#Jt��@�Y�Ud�jM[���s\�������
���Z�n��.���-�v>�W������pBx��`���6j����M�;���sK9ttmDN=g���Ci���4G���G���f���E�c~���J���;[HKF������;�DY�>X���~��kd��80@����}�gL�h��,a�^�y������Q�h��E�x�n�����zMNF�rO������8�	0X
W�\)!�!����~g�TX0��<!��hR e�u�TA`���_�*���[?��3K���U����#}:Ti��]"_n�Z�����[�U����:���&o�T����#�C��%Sw^���1��q�+P����t�~IS`�%��:7�B�Pzk���^:����,�cA~������\�A��������q����b��[���K}�NeW�(x�������6L��`�7�N�uV�C�uh�bM����~Yj����O'=��r��>��%������X��_����=�c�u38�xh��O���A\Z�t��o+.�B�M
::�+���[����m�H��=�5�@�y�t��wM�y�*�mV�q�z��$�"��Y#��mSi�Y�������r���	}zR~�U�>-��m}�)7Bj+����%��[���A��>X�Vl�W�
�����u����6P]��Pp/�)M|�lf\9@�����8/�0�����\f�p��
y�W�*���o�������t���SJj���c�
����������q���	���SV�N`�Fg]���b3���������*#X�*�����Blv���B�
.�
���5�~����O�$tH]����1=!����@ Og���l� ���~�i��(�6�6��(g��	��!nSHGY-���b+%��<N�9�,���x:$]�4(
6��� ��P��1�.<'�A�B���Q�^�jf
���fa�K0���p+��ur�I�I�g���~�t������6*$��Z�~r`$����m(��F�7�L��f%����St�)�b�a\��@��N*����s,�)O3Bl�L<���%�!��4?0���p�I�#���;�Z��`�B(.������X���w��m���:��i�:��118oc�5m� �7{n�w����*����p���=��n�V��48
N��gv���Z\���EgP��`}������e�����{�8��j��N9!��nX��`�)��_�6Nx��<�
��{�|������I�a�N�Ax�ex`�wQ��G�f� =��n�8r/��p��^]����Ua��/����D�>v�K!���q�)#&��[EZA��c�l]��a&�)�@��	2�h����p����P�9/I
�+"K�.;�x������S��crH�����t�?��9l���|��)^��8�����M0�d��<`w��]�L<�4�n��� �5qu�o�H���_����������W%����66�4
�w0�x�}�>�~�Y�y4\�uY�u/�p^���9�	3I�b�)*�����=�&����NnTdG���>��\������v��m��!�h
us��"87�k�Nt�M�����v�0Bo�8-���UCaN�c���"�r09����_�)R�����
����) �����x"X������\?~�����RGn�x<e'�r|�m��_5�n��=����$�-:���\��h�.��
�8�
�i���4n��#��&��Q���R�E�w9q0����p���k���8�^?�	�7���Wq^���_��%�z�<^�����@I��%GO��
������;��$wz���q'��j/���Zv����@��]�Z�\���Hj��@�m��W����}-{��T��@��#t��^S@��5t������v�j�+g�t||�gA�]v�J�y������Q�x"*��q��<vz��~����v1#�������]�xs���>y2�d�x������^@>o��;����/�C�]�#h�[^�n���n�.B(P���}:d�C�c��o��4�Bm��e��i�,14d�-�0��m$��������:'_����C�g]�Z�)�X�Z�K<]�����!�^�Y�n����(��&�;����������n�����a�t�7�6������U)��m\�w���������U�[a&��S��j-
`��7��$F�C�h �L������:Z���B2��S`<W�BW�!�)r|J!����eF�2v������|�25�x�	i)���-)�����2�;�����x�t����@DFPG�&_8d�H�$>��]?}t�t#��4���0�t�f������d��m��i�1�16ga0a�����R�m�:g�+�0�������W����z�Wc-�A,�S�|��7��Tk�
F���Q������>`�S+J�b�
H�����0O:�����}�I7�on,��O��(�����q�u��0�y!(X���X7��1�J-Dh��Q���M7����[\�j�U=:Xvi�A�w�B�������P������:�)U��8U^|7e
S� 2�\���Bv���^�Z�a���	�4M���#��}��{���FG�>�i�1��y@�����~[�em���
"+1P�V ��F����(�-�{�Z��n�WA���%����b@3F��z?�<m��^@^���7,���_����9����
A���.:���e����R��R�L��j5�uO��2�~�e<R�8�]�<����}��x|�^5yY���ogS��!0.F<%a��K��:C}���:hT�����m�������y{����s�)W�����4Zw�P��!Hc�����l�����qx@���Um���`�d|8P����d-	�r��2`>��B [?�C������B�w����CXH��	0���?�����H����KqOk|��3s������
�D�d���� ����d��Z�����w���	S���e�;AS��hB����k�-���n��t<�:OE}���*�V������"�.�����8Tx�����<(|�T�����4�Oe0�^�9�����E�s�k��TW0��'��_��>l��e����GC�7��>�N����j����C��?f���E��B8 C�]Z�Y��fm�6�o�#Ro�X�I����K�������#����[���K��k���q�k�'�_�������>}��z�A~����s�!�6x3�>����7v�����{0��<���.�f&��2�����/�S�
�����gC���W����_PL����W~���-<�J1�I��������\K����Gx,_T���G\�Z����C�d��*�c������G��/���?5������K}���)nF�8��K��U�?�U�~������C�p�)O%��5N_���UT���e[�1�8�E�S�Z3�(�zc1Bv��`R/[�s7���'J|�9(���d �GYe�0�y�*��I�F�y9  �W���1m�^M���A�!��F���%EI���W����������"�N��>�v*�^����Z�5�I��<t�/s� �y�/>�t��!s!]��7H
B51���Wo��	�*��.����E�|�*���%s7�T�l����*��Y��(�t3;yY�+J|5�|[hn�
����NH�w�����4t��Z��(��a�%+z�ee�@��M�D���I{��hA��jQ`��\=~��D/�y�t�M����n�K�V���9]muJi�I(r�n��(���'��b���*L���tR��w�K��O���Y����GG��0�`t���ts��hd�������8���!a �I��^���y3j����9����B�|���`,�����T�H4���p�������@�+p�����a_%��@�j�e�{�Z>c��<@B��s.�s��e�YE������;t����T`\ea���w=�	�'
!�u�N��)/�D��,v���(o8,=B�r�����S$�^nc�[����j��i*6���tt����q!����Iq���t�gU5�H`&��|��%K7���d?/�L�H1�BMsZb3���6����a�\��Z�]��H�a7i�-39�����a�8d��c�������5����P��7�������>"����c��t��T����K;
R��V&�8�#&�8���kL��H�0H�6o��0Q&����"�Olq@��&jN�t^���1��;���*
�JI�^�(�YN&�u1�tG�{�����lU�9����]P
��9J�e�B#�m��/����uymP(X��m��W6�C����xw#EQ�\�Vx���H��[/n?��V��r���E_��_�4�_\t��H����������������:�Z�- 8C��9g�bYH`%��7��t|J��]�������{�>H���������4.������k�C��������� }�j�����`���������<����=�v���N�vJ���t����W��}z������=k���� d����!%{��d�����;=��>{
������^���N�(^�LJ��o<@������1�?�dO��
(���O�@���������v}6����]��G�0?�
�Lm1P��H���r*�M�pS	��l�a�Hq����������H�|@������<i�|]���a�?+������o*(_
x���lz����5t:�ho�����Y�X0C3�1P��M=[[���je�G�['����bA���{"��V'�G�ge:���{��e����]�qF�Jzto������z-�J��T�d4�s��`������!>>�wJn�W;n���<.���1��I���&��4Pz���]�oW��#�������\������:�������4C"�������1@�<��b`B �����P��c�u�����;�q�7�!�e��8�I�����d�N���w����5����LQ<��	EG0���n�[�Tt[�/���2q|���p�pH��G��'=���X�=����J�~*je���B�y
��u��
�t���3�kq?:���E�������|��������V'����?������>�o��KGs������w�����GY/�50��%&�FmF}��Z6���8/�����1�~�o�&�7	2-����jk����s�F���O����A��GM1�� '���b9Wuu���IJ���������*^��:�lNp^��arv��������������������!�����4���*~x������4����KEdm�������������=f������������w?�39�f~��8/������U��7�������������?��������/����|���<:�S���������d�Xn������|�x&��x��%<��P��^�c���8�	����5\�����6�Hf����g�����Dr����t�H�h���p�!�ew�^������pV7r+Q~�^�>�������������Gy������qK���~9��Em�����~(#E��=S��?,�A���}U���}z��W�G�\����z�Y8�e���y`=�����c��1N�Q��b��5g%�%(E�2a�j���c1����`�w�&D�pH�_�8�	D�,�u&�}�k�[PV�o7`	���vO{��#�9g;c����.F�t�;�`�����O��B�������+�7rG��F��yU���B�(��/��e�c��-��w��ca�������O�k�D�+h���X*_���{�8]C�Ru�`�O��QU��z��_b��`e������[��W�t�E�s����y&�>�U��Crp������_m��������w������
����XL�����Q��<��#���A]$�Y��|�����^u��Y ����nd_d�9�Sx�@�j��:h\@0m���>��l��x�[�p ���}�3c�c3��g>T�����s3
�&.L�_��(���8 ��W-����7r����9�o���y�tn�Xw��&W���LmR���x�,#}����	��^@��v-��8��-����%�A��|="t6n0(}���s+���Z������!�;��s�����r���_�9�W�6��9��S���q*^������u�>F�������Zj�>��0��,�y#�jB(�%e�{P=/S��G/+>��@���G�������5�j7eq[|DiV�D��0w������A�	DC�_�w�_AE(�B[���k�����y+5*��IK�s8<�!P���U����f(^��r
/�0�W�gc����`q��I�j�����5�qP��m�Bs��A+���"��������K-�=�#����k���8L�]N/�~�Y�Y����VyP���z%�*�a�����]���0�v�FK:�s!.�G����pp��������?/{g�j��B�O�^s�[H`ic���t�y5����Qe��Q�F3�Q�Y�����`���X}�<A�����p��z��:���yA0�7OR6������X�����K6i~���	�f�����%�&c�mX��h�x����e7���(�]C3Sc�����_����P�����������[�R���������:E��|��NU���.�YA�`����Ew�����g_�2��������Q���d�^������5��Fs��-���0KIlk��n:�l��^TT3z5���1��B�E;���J��.�#���>���x�L��:�^VY�0x��Jx�8[!80'|��9:��!	������2��$����#6/t~_��������O��n7A6�-�wrI��|����7��N3+U�����s�X$�m�#T���x��K��vYF�\���22����T�4���L��d��)��(_v�*�a���6&2���1�����i�[���������#(Wzdr�w�nr�E���d/���5����og=���
ft2���w&�N{�K���y����Or�k�(��P���e����*��`�-k�uf�
9���J�2�p�U���4��fP?���L���B�D��g�F���@�TtG�U_�3g��"�+���i!���
Z����Tq,W�6{�#�S<�{��+�/��fX,���.]_�p�G��r�;FF���d��LR����s�JcB���g�sHG�i��C[�n&�f)��B��5���E�:����?f�jz�YkJ'S�&E������B�l*�X��a�a:�{��-��i-*D�:lM�c�-?o����,bc��D���u �J���q(
�:��_�k�����yl���Q�a$�?9�1"���l0�QK�����o�������s����q�E�V�gD�X�����bK��a�;��:���%�1 ����t�+&�*�;S�����h7���,\��5�w�(���K]tO���XoL����/��iX�I�q�W��@���\%-�S��M��*Z����A�)���3o�@������3���	V��s}�!��� g?���I�7��<�����x�8��Z����6�%���nG=]x����a���A���]
�����z��>�����m[r&�������P�P}������>P���������hb��SE���Xi|�8/�p���
n����J}!��\���N�9bo@�@�fS�C�y�=�����^�
u0�Q-�^��!�\[<��bOv*VQ3���
QN����>���ta&�l�.�z�6y��:����B���d6�G�A��[co9VZ�(���@_9�cIK���A�������x���w�G��X-���(g
��.���������p�����9�&���*0,��%���
P���es��`���Y�� �e������6��	�Y�Y����Qy��S�5�X(q��fy�}�6LI.av��2�<a
dk�;����Y�cW����o�5����d���%	�`E5f�U������1/�U�F3c�o@�[V09���<vV������Fw�D:���HN�����>�T������f���B���L�s;��k�LR��}�J(����S6�����9z���C��}���YTbSc��5����Y#�yL��f�����,@�����'��2]������5�.�*�[����1ia�(�o�i,81���>f��|~�S�����yZ7���������s�h�LD,�6�B�GL����d:_�b����������,�� -���`M�Cm���;0f���=�c����b��S�w���x���N�ko��(��S�X%7pj:�Y�+���3S����:V�'/vB�v^u'<���������T�L�Z7�N����~� ��oh�_������a�-V�� {ob�Rm��W�?�X�[����$�8��A��".6�����^�0"�Lv����3`F�n`����7��������I�9p���e��G~�]�����,��'/����y��,*$���=m�Ud��<Z4��y�e�6kg:UB��Jc��\��L._3��o��|p�~�B�������SH��B��R�W{P��LQ�w���C�\m��d�msb�xGX�,��5K��� \�1 z�����������`us��������{/	�1�%��C5}��h�!��XTWE�������w�^(���e�*]���a�8�>����U�d�Y'T�G~t�>�5A�OgM��Cm��1�|S�s�[��>�9�p�HXo�o�9H���:�+9'���0�"t��4x��I���^��]`�J�@��4���py����.�
�';7�X����	���P
@����L:�F���N�F�����%��qH��J�R��4f��������
�"�#�M\�@�
>KV��>y����P\��cU��e�#�k��=�|#=4�>�����HK��
J!�W���h*
I��vY���z���1������yK��u�e-������Z��z�5'08v�;��c]�p�EO�k+	/���$d���}^�F���U
�E�45
iI���O�[|�/ G].�ov�����*�8Tu������T`z�q"������nme�8Z�Q3���q����Z��ZcS�EmVW�������T���6��o������,&�����d����9�v�����<�|3Xa�c���bb`�'2���uq�v�Q�u��:���4g��G���r��U��G�Z�8$�>�,�D����`Z��U���R�f�j
c/~WG����8e��J��k�����>���
K�W��sN�a��/�4\���qe������(����AT����Cs]��;E�-�
��NyHBZ����Q�������cx�O��:/�;�%<��)��������b@����
��D0	s���*<��"����avmke5=�"�z��oU��5�z���H����B��9u$s.%�s���83��7�M���kJ���l���]c4�
�c
f:��a*�{�ezS�*)��,���.PHc����P
�
�����K/�����@����Q�8���@|S��+�]R3�xe�DW�n����w�e��
,,�5�,�Xd�Lo�����i��Fvi�FQ'�����(�W��l-P�B�9�N��a��R]��6�qu�I�<����Fy9V"�%�k���}FL#�f�Jz�0{8��C���'c��2�BsV�VX�B�y�F����f/C�F�P��dQ8����e���
Y0ES�9p*�LQe�����������c����c���e:.��{)?���HOQ������l���2�����'��6�^wU�����Yt�x�9k�5�L���n�h�����u�o	�EK!�
v/�T�|N�i�����jpf��!8��cy&1c��[�=��s[W�L�e��<Z[��ft�u�{+�s>�f��]����B��w,��%�[���d��`A�ge��v��"�{����:�X��AP#�46���5z����F)sP�����rq��c!�(�eLq�n�D�It�O��.X�k���m���I�2��@��d%�F���4S�{��"�|��g�7#�
�����:�M3�Io��������4jE��;F��aN�?��_��X��������n���iz��+i	�zSS��ne����a���!�=$~�M�Nz�"�!�q��Cf��7.�m66�B�,�\�?����w�[�!i=��O��v,,��a�6�I5�:���5���.]���_�l�}��fb��'�~���$V!���g�	��?�O��\��-��I����miz��$���69���)E �+�u����\&\�Bm��P��XnO�S���M/���A��r@�^��u����C�2W�Pf1����C�t5�6�RhcMcP�HG^~VV����&~v� �v!%�T���e�<���h���M�o�tc%E���+���Q�Hv��������6�z���S_z�%"�2��^�F���G��?p�QR�4���Z�^`�}[*E0,(�g�����:PW�� ��i�q2_�a����s�8+��~n
��Y"��\r���]^��y�-�1D'��l��o��F��PU�`h�N��
)l7!���l39Y��9A��y�VY���D���@DE�R����e��t��l����l��"�����\,�_�q@������)���e��������@��]�
��2��[,ESrW����BlV�g�L
���to4�rrZ?#y)jYN���R��|_�is��BLZ0:%V��P�3n��>�����Ov�����b��_S����)8�$L��3<�LS�M7R��2�8��8���m�G���zLz8�!.�J=��z��,]n��Y�5�r7hf��+�
��*����y�Z����9�h��o
S���aT2%���IY�
N��F���#�g���&����0Z��K�C{e:60��hY��qz����{���3���<1���z���cp����+��q���.6��>�'�t���r"�#��,m�������>�ud��Q�!� ����v��M��^�xPV#���"�3�����������D��j��c0S����
�@a���v���f3�NBCI^��Z�+<���~k�:A�����Dt���x��.�g��D����������H�XH2���L
��P��6��B=�6����XT�s�V��ta�
��w���q��Zn���W��qD���mA6D!�b�E)`�c
"�}u`�P��X���Dc��r"�g�t��865��G��N}��C���j�9�k;m�aL@�Q��#f��[����,o��{��;�O���i.h%���p����(-�/�.�4wIZG�8
Z��JQ����a���������UK~��
�����t�n:5rH	x4�dk*9�<�����k.t����v1Yv���?� �e��-!!��F�Y��!������ZQ��r-�-t�k6a$u+conJ&���T���,��=��NM^Qx�&V7Tm���	t��$��������aQ3b���,}s�!#�M&	,	���F��HH�zD9g�8�4����,�V�7�C���MLGLJ�T�8
7���<�L�Up�OL�c��>)&��x�!]�e���$e�q�u�&g
_�nL��l�� -���=�.*�S�.���(�py���}]�2Ah���y�,���p������9������RS�9�����8�)�����d��5Q�l�Th�G�eVD�a�&e&�R��]���E�nq,��aGfF��P"Nt)�.�<�m�W�df�t&�hu�n=���b���ZV����Nu|+���V=#T_�iy��g��v�si]q�A��^�X�eq�I��5�J���6���j!tg��K���r&{1���e��sC�E��rf�}J;��A_��X����abd@q�.Y��A����`�P,��y\��q��zm>������7$���G6o;��q��{45BP����$='E�N������~���
L�*�>��w�Z�����+y�;�5�Z��]Inu��K	oC�4��T+GF"�I�(���'CkJ�q.�����!m����'�g���5Y�"�=�fy
eC��Y'��^;k1h�����/����0��L��KFJX���l&&��������r��4��`��7�.�	��u�H�-��&3&���������w�F�h;����6K����d�-#�M>��r2�$���C;������d�������.0G������-��b�G3rM�������D�z|�q���%�,`��=8i��CM��x��0�����l���9?l�*U� r#�-������x$r����z=����5�P�
�1��=��'nEp��sS�����Xb =dF=O	y�2�3l'����=�?�������IQ��T�=��g�+����n��W0��9i������}��_�Ds�(�B�A��s�e��@���e�p�h�%�z��`�V�~S�S�C�B��� �1�@{�<���Lw�@"�*"L�}�C&g��Y�Z}-�&"C`�)=� -z:�������8��p��cT7�[XRq��@m
*�]����lU�Y^7��B���8�#qX-l�D'���2�����@'wL�%���w6�����`W �l��A�{�g����oK���7���,��o�
����$�_	+_��8�
;����N�?gi~m����:����U�Pv�4t�pR��R��49�aeq�B�!HAs����/=|�:x��Ot��������;|$�B�:.����Y�1e~/B��*�����N)��=������y��"y��@{B��Pi�!�F�S����J��L ���p����m�s�N�������<M�@m���u�b8�:=�j�Qc!t0�$;����@��r�0Q3���"BZ�����!>Y���IY��]�h��UX�����7��f|���l6?k�)*���{����+��.|P��16�Z���r���f4�(-����[����*����%��M�ti�v��Xh*��E���-���w�.P'6�m���+S	�
C#/��������u���!�k6�����/��g��F��1���5�������Gv,����+���W�[~�V��*�*���@4:wfp{\b�_?���N����`0�����z<�N^�k��sds��	��c6��:�rS���Kw��Ia
�Vh����P���;n�h�L���*}�����[�h��;Ur�����Q��M�&c�����t��>�_�hr#ml��c�����C��E�u�Q��E���N�f���8u���(�iV����E'��=]��c�-����
c��J�M��:.=��g?��]�u�S���*��������F
Rr����3O�}��[:�E/���-+(���G�P�O��2�!��H��H��z��E��m���R2��sC\!�XbV��o>�A�*A�@�J�����^��|�D��Y���,
e:&c��O��v�mi����D��0p��(BC��,��H,T9x��������,�j�Q�0�6�vBR��GC����:{��a~p��p��h�r��pe��c�
�6�d�k�*����Q�r��#�����?�Q�:� ������X3�����������cQ;wH��s���$�.--Z��n��H&�����rh������i��=� M>�@Y���K�l�7��|�9�E��Q�*=�����E��)	�"D�/~k�nv@��SP������K�
�������.{r�W�f�Yt��@k�M*���QI���C���BG	Hv��0X�}�'4��.�L����#��:�Ash�Hg���1���
�H� ��a}sj�.sB��.�X��]���\��g1��C4zQ�W$��=3,����6���L��Em9M/6u��b�b����%�h���Zr#��(��FR��+���T�EO��1O��g�����6����i�@b>]���^��H�0*����G�
���NV��@�:��p���cPG�Pv>�{������,��q
��)VWPG�~3�+h��J�{o��1��V��b����88*���nh&��uS@��]���#����OUW������y�G�=*�4��+rb}	d@��j��A�dyb��?�i��O�viG=��6�����ZMl���eS�R�,4g t�Hi`�!(C8�hskWK��`��A�ZOk?".�}���|g�T��Y���{����hl�W(��� {���H����p������?��u��,�2������0AM�k���������ne �����A�vA0�o�[i:��R�/8Tm��N����*P"F�9���@c�qzhPG8���i��&�<�!�2�S~P�����X|4 �K��%�T��L�����*F����
��Y�������� �T��*��eP^~c����&�m�����	?C�gi��a��pN��������3S��;���$uol�BT�d0p+��p������ai���pt�k@jl�(���������������#��������A]f�JQ{������N�(/��I�#$��0���t�����8y���y�y�b����s�����{B>*�[���r����(0[Q-�9j�����h���<8ESt�yMI���(�����#R�W%�I�~�B����*0���fY6R�Y\��?������B-�C��(+�7GC�pO���y�1���S1��Hu�8[�L��r��mO|����=M� ����� �Q�2�_���������"A�8�6]!�P�q�n�P������FW�����Y�p8EY��B�h��fP6��u�����?��!pn���N�A�wq�I��\K�
�mx��
'�!�o}� �,���P�q�*��u���T�f/@C��d"����2��f�0v��{I;A��v2�dH���V<"SO`�1������������������I`a�)����v�����8�|��> ?����&��+RQ
�r)c��|�DF����:�^?�uA��pq,����a�Hwh��[��#����x�s�'��n%��5�t�T���������!7����Df�"���
�V���G�r;T��M:����Ce	�<�*�x7���+�d"�jo��@Z����Q0	(H���
�����I�n8�WjJ��0i&ZP�(�C��L��aY�XamS:�����1��H{��A��JQY��@0C7Pq�:B���~("�2�
"��A
Ae�0��������'�L@e�] #�6��B��>��i~�t����&������VW~7������y��r'4���}��������AB"��.��SU~u����K��mV7��v�Q������vA���)j��@W4�V-D"x1lX�e];���1��J�V���6�&��?%��U�$��[M����r�`#��������.���Z��-��"?s�7dI���~��Zd��:%��
U�:�Nn���{1P6r�=��,��Z ����/#�B�h��u������124T���)
X�U�y�F>�B3H�r���)�+��N K�[<�9���
88�	P(a&��VS#�x9���bS4��T�����T;�f����b��S� �\�T��a�b
��g�$Ey�C�X��B��Os��I����N�4p� ��N#zC7e���"��X���<H����(S ��{Q������F.K6��y�0B5���}���'�=���9
� 6X���(uM�/<���yo��$���D/F���I�EE?�wb�`��M
�\���:�(�~-S��V��O�����e���b���cX�R�����[��j,�K^k!J�gB�D�k��A.���!_j�p�, ���$���v ���H��
�X����nrh��|>�Q��("$t��d�,�f�YE����p7������^?�cF�`��>�C7�9����O��0cI��0=@�[Ha$m��2t_�VC�C���u���ix\���u�������(�V} (X��@���hX�nG�����ZBE���RA`ss5�����:,���"�m�� ��P��7�`ds�C1�O�j���b�z�,^�'�����e}�BOT�yf��J��:~���L�nq������J�Q���6/%�p�b�_~�
��r/Q�C������83�������n�����|���N�U�j��~��!������_�+9���PQq>}H�-�F��eKt�wGG��|�{!��p�0�\���gA}2u\���W6�T_?��q��9�@���I��6~+�te]��=�E7�3Y�O�*�A��Q�j.��5������r�����l�by��
�z����C\��1kr�o��J/�ljd�6"A;Z�R(�eF�@V��S��V���YyT���E���|1� �����rA�E�h�������>:�tH�[�cgnK����Tt]sG� ����/���������OE�G8tK!�q���@���d(�X�z*�!�f&9,,�A�	R5Km��������DP%P��Ad�S!p�������d�.k5?|�-]���]����4�"��������U� f�b/�Y���;mbp+��H���.9MbE�}R#!��)�q��X���$�0a=�
f����U$!�d���pH�IL����F������Brj��u�V$&���;���or2� f0��*R��+1EP�.��'�P���W2��6)��b���
5�]+���k�K�����Y���2�Q��T������OGrd<dwT/���CQ��Q'�L� #wnR[�N�e����	�)���Q��1�T��^��]�*&�aH1)� aD�����'�"��jTM*1E�X�a���7��Q���V��B�K�+��cfc��/���ZfHcF��T%RFO��hW�\�	�cj�EU��?�/nf��Y���]�����?���-(�A1I���$s��
����7k���G��_���xO2�������F��z��b��L���3Up�^��^��������0����VC�pF�B�X5DP~Q^��Y
����Q|Y9ER�����4*�TYWy�rR���~��r�B%����'
����^�&��p�:#����+�����;���������/8����a44-�X$���do�#Zp��*�L���m�T��H��.�R���D�o(���6���`!A���7��.j5��]C��G:��u���o���]��I�Rv9T�md*�S�j�N�`���\�TG��7LB�p���Z]��JX(@3����9n������St�nh����S@E��aD<�kN������u��$�e::�Y�Wx�*L���:���v��!�>Kz������B*M����F�UeAar��4��� K���0�	P���kIP������0*��(
1��1s�������?+C[v�T�V���Ig'�tfTT*`>��@dg�/��X'������������xx�<L�����8DW��>(����zR�������bmX�2D���O,4V���QO���tr/�bY�q��48��
~U2Q�:x���1J�\-��!zMr��M��k-b:���I=0��7z��m:u�e�2[�	�����k$�A��(�����A�����c#�9���q �9�SU/F�k
�M���P�7�Q9H���z�R��v�(` �#�U:�M����e�(���
�T�n��1�CR��P]��1��@
�<?YZ|�]��B4�,�Y)�E�6HTg�TQ�=��t�V"��xl�� ���z}��
�"M�A���
�����s��[��!��d��WK�	T�0FUA��X<B�8��<��@�M�t������kC�����"B�Vt���!]f��0�;��
����d��kU%�X
9�+��hD�e%�4��Q�*N���'��@�c�3E#�\A%Z�L����(8�_��L�1}�����MH�C����mq��4��*��B����z���R=a`�^�T��N������^� �_���<�3�;	Wo:[�EB��d��qf�����R�Q0GWC����)Q�Q|%
:
j,��`�J�����t��l	L��#�� VQ�z�������x�!������J�U`�u���6`=`�~9!�������=�&����O�b�C|+%$�X�?LT��f�.���x�D]�P��Y7\� ]���6��*{�=2 ^�w�
9c���tt����p���<�.'��`��PHk8��m#F��"��=}�+cS���$��V4Z'�dH�
�
l�����B�Q����i������E���`�����,�1�g�U����.|�0|�BhN�S��� ��*{+b��JD�?�$J�����D�F���!�`(+������������(^���>�EE�!�d^��Hb��@��
 *�+�����m����R�@��ny����b�j�&k�`�{$.����j�G��@�I��H��z>���!�&�h�N=�C�N����}�XFQ�x���hi|����)7x�.,��T��>��Svai�q zD�3-�=��Od���_/��MIY2�H�RyUD�0��0���@���G=j<U��D$���Z�G��J�P�����3���*0��U���wb8���C����������E����-(:�e����q+W���x)M�>���dt��Z)vR��b8T$��.�<N	CX�;A.@�j�V��C�^�]��L��x�2� �9���]^�zu@��
C���B��0���U�X���\�^T�_�����AKM
Q����k�����9��a�p�l��G!��l�4!���t7���0��(J$�I�4C<�!F���mv��
;4�NM����*�?F�[S�����0�����6�:��u���~
���  �23E�������h�n
�s�XwMY
���aR|�.~�k=J�4��z&���P��?l8o�DM����.�J�$_O�fa�%��H&���y�W�+v��]�k<�3b�-�q�B�0����.����.�Z�Pg����N���f��1�&nT���?�t�l�9	�d���%�T���T�_�����]$e �K��K�'����x��x��d�>"=)!E�P��p�
���V�p��g��(�^'�cc��G1s'���'O�xM�Q�:'_�u������yM��>0�m4n�C-���R��X��,��T�gV�����[�}-/&?I�/~�P�b�DF�W<|�������5�
�$|�us����>
�T���<u�����B��'����n%;��jd�B	��L���@v���\U�}�%f���PC��7�SSq��w�����N����W������
R��k�q��@��AQ��N�m�}�kS`�����A�X 0q��z�GY���Q�U�l��.0Q�Q�}b�|����V��C�R0DX�����;�-�Im�y6��w��H�,s��m��Y��@K���l�T>���H�ZFxF#�!Q!N��	X��l�TQ	X��E3�w�,�64].
�<6
���B�G(������!�{��v�"D���S�c�agn���1�	�����/~�&��5�f_��A�g�zE����4
��pr}Q�����
������������`@�Fy�S���6d�M�tPS6�I�GIM
(	C���r�gC�%�
�����U��
@g_�s�a4���Gi�0\t��y���?E��:���7Zt��I
R��'�L;a�%"��+E����R!��:�9�K��\*P�E��D��~8����n�
�o�����\ ����Z��~g����?�WJi(�Sf^U�
/�K����2�rx�����(�A���t�~��I�n����EGl�b0�Z�����R����e`<�=L~�3*T�z1C�'X�c0T,pL����{q/����M[�����7��kT��fR?d�f����wOb���4~�_�3�"������^�u��m]"�W7��	���G��s��0�}*&Ag�u�=�h��IF7��m���5S�
Wf�B�8*�� @�-��%
�_��R;�O��kSq/��&g�
����d�z8�)�K�)��W��@��qn���t��8�Q���D��V�E7���ka��l����������.�����Q�`������{*�1U����#��*�`H*u�g�{�����������a&���e)UwS�4L�O�5X�=��'���'t�<jst��gu/�E
���k0�4=o�0CW�P��&����b�T�m���)�k�>�rt��1X�?��e]���^�`�2������D�o8�t8�o*�q�<Mc"������nR������%4a�������d�����]3��WW��,>T�u�	�Zg�
����yv|��t+H��q��

?��"�~"#Q��
�]*�������m��_�~�E�)��z���>*�!O���t#�xnh�����Eh��q���1���5\90n�E��o��\�n�����������`�/Y2`��d��������%�x���BkD�C���M4�t	�%�����qTy=�T�)��X�T�s�6z��{Q!�D��Z.����0�S����)�F��+����<����W-��	��3�,���H�t�g����`����g��{�L� �1P*D@��
3�j�����C�eu�	F���o�v']�q�KQ����������I��]�*����i7�5t�����;�FQ��`�s�"\����4���:�CF��R1\�$20�_�(�q�����j��N7�;���a!��u(����h�xG�t�JXyR�h����*c�Q�g��Q:=�0O�k�`K)�
�4Q�FV+F*E����e)�����1Bs�!�!rH��9Z:�7/��xTr� F-�y���m��i*/�`�G�3�"�����
�J���y����f����z��h���=)Y�
aZ�Q���flG��FkeX����-����-f�������� �CA�����H���;�o�C���l(|M�:c8��A��1���s�>?��;<��/���kt����0���jBF\�S��F�`s��[���8(3
��>�;��!���
q�[�A�"��b�%Q�0��J&�5(���E�r���M�=6����u����ZP�_E��I�""
!B@����U��5j%�y�Y�=�W�YU��0I��������Y�^^������0��L�.$:���Z�����P��Z��B�h��Y��5#�y�	����wx�e	����nJ�j����	X�l��T�E����i�:=58�d�
��T�������A�!)F��w���
/��r:7MM�)�Zw�^oH�������}#���#�Q�F}���
3�2����.*�\;�5;���^�*���#_���N�*�G���qQ��xKct*���.��'����{U�K��]�Rg��3e��xo����
��M��$Q�A���j*�U���'e���1C*���yQB��o@w�S���w7��K������4�
vn��=�x!���w�_P&������k>������v�t�����?�W/C����'�[��E��+������
���Y�������6�ss�o�a�W_��;�����#n6d���vV����o���z�*���{�����~�6Y�gN��q=U��v����}^\�t���6o>�����)�G��`b��:��������g����p2~�~�G��8�����u
�]K���u=����>=��i�UM����(kI�?������D������i�]�=�����K����[���%��?��i�������^x����m���[����/�g������?�o���~^�[��K
�;h��qW(��
�����*�k�o�Y����X=0��� ����&��+���E��������`�������#�@����o��p������q����������{���������no�v�����������������^�o�3B
�n%�����s�������n����K�����57i��e�y3�2��A�{����&�7��M����Q��������������M��������5��v�E��_��-�/������^$�Xf�Q���8�X]�t�t��:����>}����.E'+��l���������0#��'E�(O���e�*��P MT�8v�(���}�}���1���{��`�P�8Mh������lG�]?�����Q����$��{Q���+R�?����bh��]%��k��2��]bm���%(#lF!�v~�6lG�<Iv�w4�����Q�l���(���������X���/������X�c�W�6�a��b�3Px~����Jn.h<@&�Nq�(�8(�.����2��?��a*��&�y/�gb�3%���aV�P�%��~��@��w�[����8���=��O��K�;�������8O�������"�c�e�>����;���A����!Q���x\eqH~��v���o��7��|m�k[=�����T �����8���$�A�_��\re�;
����n�'�����#UB�^��9d��j4�)X��g�������KMfj?v^A�(�b�,������ P�p��X��y_�.nL�&$�M�l�DJb���x?,4�����=+�uv��Yh�>�f�)��)�}�������������k>���dz>pVT����i!/yj-j�k�4�dF�Z�T0�9�&'d4&QY��v��m7a��B���
e�9Sa�����VaKtAg�s����i����,�9�,�8Zyv
@^��f��B��`�o������Xw����E�����>��G����.'<�>T�v(�^�S��]k�@V��c���l^%���zo�{�7J^��Z�[������?��g�o�~Q��f�b�`=$S���d��Q����Ko�0�-Cq	�p���>�pp����,�����2��^Zy�?�jF>2	�_f4�l��?GSZ����N�J����_	7�d�d�����T(Z�:����]S;��������v��B�=����{���->>�M�1�;F��,,g�uOl�2�{�a�vMk���G���f=��{�8�VY�JksX_M�K:�2��2�G��Z���i�_-��U2������_s���a�1=��L�,�M|#��#9�!��3�-���P7�N��R'M�0��������)_�s���m�l]fC�:��o�jR�]i1'�y�9L���Z���QB�����\[�r����'w�ZU2Q������T[k�������1�r����!��������������'����P����^N��Z���}�I����S4}�o>B���	O������^xt���K`QU=�����L&:�0���B2V�P����v���BA��&��{�S	��2��E}hF����)��O���q�'���u;�,���Z��R���$V��(�Y}������Zln�C�D{)������
b]
��%�����.�@UK�G�/\.B�	�\�����z�����%>c�����������������������e�'���X_<�/�����a5k��:���������������Y��2��S.�{�}��5j����/��6��U��g�B����1t8�P>��heH�<u�a�I����2�6����������y_��u�c]�eon)H���jO���`���	��u����t��vL�9'-�|����\�b��Yt��on.C|U�`��*y���4�j����������
n/�z%���d����M������(��E��Z��
s����9@�e{b���/�%Q������L���tA���'��2��Ry������N�FMF��m�����'dE�M�#�tE����.9.n>B��o[�:#���x��
!�$}�u3n�}V�a+
��B�P ��%��F��<vqef�c�.'98�E�?/J���s%�<5$W�E��xR�	���u3����,��������.�������7��e����\�YkG��&o����p�MY.\���{re�B��2�{b��_��4���V��������������U_gF������m�vj����n�v9����"��I��m����y��-F�_>�����sQ71����p�����������^Tey��8~}�����x�Du{u��S~���P
_S���[�cr����(/��0�@�]�?��~2�M���PE���H�$B�~��)��7|�_�����n-n^<��_�|Iue����Iz�]b#��P<����w����������������0k5d�B�����[��J�j�z6�������u�A~L�N$'K%�����Wt*��!Z���_����D�������=�6}G�@s�1�b�U�TV�o�^�+�������KYyVr��Xr0Yc�z��������_���=9|P�~Sy��^$t-�ZA��.�uq���F��sL�2�����[�C�2P%��5s��t���s��9\#
���g��Us�0�fR����C}s�q�(��Z��b�O�|z�/�G��!<���q����?�����S������k�O����$|�yS��+�SWs����i��P�G7Y(2�m�UF�]+9�)u��k[yzS�A��W>XJ����o7C^)�"�&�u�����c�n����Z����=�k,��c����b���u-�oq������l����3�M�~
��s����Q_
����\Dr��e���m�����]W���Gm�����1��d��m���Y���1&6�2�l	�Y�����x'��]�S�)�D��'��n���w�?��K2�n9m����ax�V���D�u2�����CQ'�Vs���������?�8y��z4�ko������a�R��A��yf�>D�6�U`Os�=,���?N��~f6�1r����hZO+��T�z���5}�'[�YO�"5����������<d������/~�d���	Xdx9����:�m\���Z�/��U?��nGm���K��.�����*�v��nK������!�IW8D=4eV����w�-����\/|F
Z��<������S��>2�_�W�������B.���Eh���$�����������	[�D]��
"���oL�,.g��i��d�3
���m��h����T0��
�F��[�$����,|'{�g�H����.�]y#r]��d=��W@4m^R$O���T�����=X�	Em�M���[9K�j��b�4�9�u�|!��O�_���n�����r���;�[d4|X��p��u�5!�_��r����t�_}��
�R�N	}�cF����?a���6�.G��b|�^�$f��]S�D��4�,Y��L!���qkB=�O��^�g���	�Z�A`��_f>��|SY�~9�i�d���S�����t��������\�7�U����13�.���c�Y	9����e�=.w,���W<4U!�k �s��v�� ^��)-J:�������#/-��-
�r9$��4y��Tx�T��(��R��W���.=��0�MR���G�}Z���:��e5���<���5�fD��b����L��e%�����4fi�{*�j����!�>�1(����YG,�������_�\)����%��A�{~4.7k������gw�7D�p�t�r��2�]��������}_�4��(��/V��n�>��]m�^������H�|�e����@{��:*�*�v���?
xy�/��j�n[�,��h�?@h����AW�kT@�k���	�g����s��GhBEi��I%Pqa����aY��u1��UD
���.dZ���d�4�z���
�:CUS���FiIa�9�`�8[+"O$2D��B���%o��"@0JB�2�W��o�u�C����o�z4�&�7A(Ip�H.�j�:��U�e�.��Nb��n���'��I
���q��M�>��qb�	72�O������p����t���j�	gaU��R�5�EU���}���/��/'C��QbTwe����7����:Y����;`�L�M���[ x���!�oL���Q�/�x�����i�d~yq��)�I��o�@	����/�OV��W���A��j�B"�������B
�"�$�t
��d��~�#�5Ig���@
������Z�]���}U�����^<���STQ�;�S��R*f�����\~��e��V��L����A�q�S���_������t]<�

rH;�
u��A�W'8�"���^���`��A��1�[~V�uQ��f�)�B���fj��"PT\�Fma=W�x	y�3�9��k�Z�|����QXv=;���?YEG��rq��#��:����`�SAf���F9�}���,AN3*�! �7	�X}t�Z�%~\�v^��utR7�~l�:�����9E+B@�PrX��9-�R�<�4+7��K��i���!E3����a��G�e��,��j�F7��GvtxLaD�w��	������P���'�e#��"���� �w�2��c�zg/����noQ�C7�Y������|�acM&#��uefe6;O����i{���)n�O2��|��l��|���7��\�eA~[�c��������]�5��=��t��I���7�����8��s{��6����������_����:M���v�9�����4�����*h����8#��������}.�J�tG���KY�-a��)�,��7u�g�w~�9���u` �g�wW�%���Gx`�|ts9�6S�_&��~�]��z���Gk<��9#����s�����P�~E�a���g~�_��^lq����k|������,O�q�Gu�T��32�����	=9
��i�f�y�A@#.�F����s6��=V�bA�0���Yj!� 414�(�u"h@��S��hxX���Oq9z/�{9
��)E!��K?|{��KgtQ}v��f�%�?v�P�fg�E�p���
gS��S������|`q�6���q��F�[J�8����q\��;��V#No5(���Cj���=%��s�N��p�o�A���
Q�c�����nY�?��X�������
����}'�&�X�l��]P~����	Hk)��'���\jK!k�����e��B4���7���z(a���)��e������4�j~�W������o�{���O�����QK�� �}Y�f2�f��N�R�����{������n�v�*:U���g����A�����9�W	.p�Nsy��=`h��T8�X~�"��r����/����n��E!7�k���n}�<���l�g��b�s��F��p�&�T�TK������-�.to���!�4��-�1v}��=�;u�?*"�q��E����{�EZ���Dr�'*�A��Ac�o��dF&�z97�E���&���],�4J�J�T%���{<��XVRO���s@�"1|:8�$�S����,�E���T�q��g����5�}$����-���OC�s�GS8Oh���&�24>�gg�S�����q|�j��MP�kOu��4�7L�')r�\b�e�:ng��
�Z�<�w�Iy��~p2}U���(hf
��
�e��H�������� �dz���R���k���d�9U�m���s���\bM�4�Cz��(�H�I�t���O)N�N�~�_'
�
��g c"]��]'	q������R3u�o��H�v�2���?�>�G:����oT�|7
�M�	t���.���}$������4��S��
p���!��3��P-�H�����qa�W���x�
��� �Z\���4�!�	�U�R�t��<��e
���nMZ����es[�|���[���p�v,�A��[�����m����	5���B7�@7�]������Xn�3Rx�*.z���*;R)M����e��[�t�En��bt�;�6
������*��5��)�J����5^�6F(�w���a�HFc+���\����p�eN�W1mt�������<����j���������v�r�)�{�dg�QPrG"t</���,��3\������-��V��c��,S���X�"-�W��^04]�%���K�a�k��&��h
El����l.���������	������,����:���(R����0��5v�h�C�q����\0�����s���+gC��"2�S����_a�E���[���;�<���X ��n�7s����Y���G}���.N�B���<\��;�������������S���-��`F0�+Q*�h��,�g�0vR����6�I����vIj�P���tM��A��O��Sri,,\�=A�K�@���u�6M��@�=���*8w�{�i�j;�{���r��������Fq�:�~2�7���S,�����&�l���!]�q�4���HF����.ae][�\�K���6]^6SJd���b����o
B���
i�JP���R��`�w���9���c[H��vw��Z���!����g��
���h���AT����o\T�(���n�$��A�#w��jN��������Ay,�_\uR2B`*������J��I����@A���yv���_X���'CE�34�u#�D��u/B�.�g?g�����.0��c=�Y���Ul�n�bW�h5�J6����'

�B�L'/L��<�������
}a.V�#��Buc����`dar0^��ayu��/��L��KE�(���R�~R���X>/�^��<t����������e��MF#p���.u��9����/FYl�������=VSw(�UK����9�u*�?.:U�y��Fq�����h9m�R�+���9���a�� ?hf�lsm6P���,
qL�qFa���S��+
+z���X�s�F%����tTku�8�O����X�g��Q<�N��T���V���<�n�)���h�t@��1�A��v"_hP����#3}�	�rU:e�9|�%��r2��>�6����>���W��h�7!���5A/$����	Q�}�Yn� (F�ao
��&�<1�r�6"�l/)s��Ra�,�A�C��g1�5�����"Gm�:v=���qX�g���d�����N�0�����������NM�`���x�Na�,0d��4�"2��~f��&V��D}6��nor���l�BP��!.�:����eD��6�!I�@;)�TW�B��w*^/"0�O��_X�C�
�����@5 d,Y���W1Z1��DL�[i�u�.j��<�n�h��&��}�b�c�������b�������3������2�����Re��A��u:��T}U[B���6�P��X����xM��hm�E=����<��M�A�*�K���sv`��5��h"�d�t���e�]����F�������4���s�p�=`a�b�6��6�%�[%�
3�<�5��R�q�H��������.������I������w���^`oi��������%t��B���g2�<��g�6��S��������g�o�Hi���o5�u�����NH�}
i&�:�������a�}�J�Y��?��P�A����$�����[*����Ppt�U12�Y5���x����O��B��#�+wg;9z���K��>	CO�<
�<��(�_����"N�2?�=�(�l�d�AA'����ut�(~/*�}p���k�R>�~Q!P�4�[�G�c
���@���g ]���������D�6�G��U�=�0�����}�ol)W���d��T��gqk*���t���_~�q�nH���(:,9�M3�N8c��~@��T�d�1aE:���yU��:V���N-���S��C�~zo��6OY����r�,��!��U�&i����R��6I-N�7)/���(�k���7d�:��
h�u�����cR�~}V��U���<?��]���	�(��cD���l����"d���m�4�R(����lw���(
���a5��8G3���|[�q���L��0�?�qV5��{c*�	{8�<
���z���t���<�7vc+��w��D�d���Y��&�A��'#�k"k��+	�T�SQJ%b#��	�4���f���b������������k�m���I�q
{����=
����6��<�~��E+��U��><�1��J�V��!�N�eS�.��
�.�(���kU������?���g���J��mRd�P���L}5��Lf>�]b�X-�z�G��$r�����0u�&	��g3�SHeO�%�Snu$����1��Q���j��/J�8�[	{���d��d��:l�+0$EYT�9Dz,��/-���
K��l��9R>�p���X���������'�4�H���&�;t��L�8�a $�����p��o���!�e����hu���;Ool������t�-��V������!`������dE�,�����
J��(����C����e����2�F��M(�jU���..5mV?.I�,��@��)`Z{��xgV�M��WA}^�Z���O����V%(����`Al~��g���:@gA�j]\�2�T����r���R8�������{�U�.��d,X2����k��K�tu&�4��KA��@�Zy�[�$��.F4yv7�ae:O����ay���8�pB9k���a8�89��A.���HLU����RAe�%���	Iz1Vs����FRg��^�
�T��	~Q;n[OP����P��8Y���y�L�'G���bp��`?�N��RF�h��)�	�9�-@�2��p3t�����h���f���O=��h���4n}��f9����sz��
����qH����iF��2BW��P�s�ATh{�����p.����?%���0x}���;o�f���
�=�� "��@�Z�\��\s��2OF��;��q�si����_F$fS����c�)�A��[y$�P�� �Ig�k�Y%5�/(A��h��x���������|��AG ��hX/s��98MY�D��zs��e���.������S�����r�J�r��`��Co2��������OYE���4���I�������6������p��{�4�g�'II��6��}���9e�n�����������F �L���D �0��$(�e�0�a����b=������������{E��
�]���C�G�x��w�(����*�P��:
]!�xj.�swq����/�d�����r�V��
���������iZ�7)�z*
d��X���}0�zh�:?An����5�e��\u��OFSdB���j�-��kpr+�u,ah�'a�(|�F����K�Y�H�~Y(�Y�u��QNp���g����@k3��������S�~��Z�WT�e,���J���m|u���S�v)���ra�z��+D}W���f�����E��.~�����YQ[�G3�$�s�T������w!7H�/CW�-�}v�6Ru�U�1�O��P����*D�y�+��eL��FS��u�����[h�wY���!���d�>��>Li��GFc)�0�8���	��PzG���=W����v;Vh��Nr�s ��e<���Ca�]�le1�p�9��qM��qy�6t\�H)���p�0��q���Q�:�@��
|���9�����"��3K
+k�p��8��TB�y�G���>"}V��Zy��aCJ��gI"B�y.e��P�{<��+�^
� 2V��5#I��Sz��ms�P��(^�/C?��<DU��@8p`R��t�~X*��m_C����
!��U"����I+��Hm��4$����l3���~����+��j��`��iEB�/��$�0��/�:�!w�Zqj�T�C_�(�vr��y�T�7��%v�0��V@����dQ���M�Q�
�
0}g�y��-L&"�Z����$��x��~1p�c�,5�2p�SF!�j���^L�4@\*Z������������� I'���.����|��)�)�6H��yu�:�2��&)`�T���0���� gP1���*�_]U	ng�R�g,]
�F
B����X�I����(J� �5�q�j$����I��1�E�x?�d�:}/�A���0F��@1za)e���db%�Xq�PN�Q����� �g�{����du0;���O���
�"Y^�d:5�&{j]e.g�8C���U�C��	��������>�%_���+}�/�a\�&��.�]����Q�0;�N��/�
6�H��
<8��!��H�(q������4���l3v����+hti;��6�j��j��t�1��t��J�q��[P7�c�:r����S4
eg<���q:��A���-3>�B��B����Lr����MW.7O��������M���%���	qT��I����g���f�^��Xd�����@�kQ0���]��g��Q�	�2P=v����x�}U�o4�t{km�EV&�,��zy9n2��Ntk�v���cR�Y�����T`�1DR_��^ ��Cz?DiS��s�����z��m��s�W<�U����0m&�#A�@���������<o�i��o�U1�z5�����n�W���-�h>��!�&�q]�����Ov������Ce��*��0P������(	�}�Jr
�)]�R��\]G@]H���1E����@�n�|1�Ni������33��px�9p�y����8���(~0�em�	1�j{8�R;�m�9����� 9����Y�A��
������%�z���/�6�~�� #m��!��^�������:ImB����.K�h�]};)���#����K�2C=���3.�MVp��;im�,�ZG�������-�Tr:uCR�%h��X���^.W~�H10BB�t��;��,k���I�r�'������X�����8������1�$7��t�y��+O�^nf�&���n��
�[��,x?��i���*�)���o�p�����b��^'���xV7����<\��a5�Lv�u���es,PZ_Fe0al?�\�����d����,�
���L�����A�?��m\��~6�����%$�uY2��Z�T�jc�zz��G��C��HUXi]�	;q���s
x��}	2tx7�\��j��^����������.yy}�pvwW���k����*��r���8���mz��9�v�OW�y��nW�y�M��7���n�cg��q���J���_f��A�����PQd����&��><$������Q��@=7d��2����������[�|[)��?��Lx�C������!���t/���0�%_�Zd�;4�o&��:�<~�2]�1�����'@�3	R�#4\^|�>?�\
�rPv	!~'������@TR��8���JD\��n���4`	_��b�V�,�O�����F��e���Oz}-M��+ f:�;O#c����g��
5�]���T��G�C������U
Kt���Un�`G��Y��<��V��(T�s3.5�:d��2�q�������,�\6�&�7���i>-�[��(��M3��[{��1��mz��L+�QA��uX�a�RD�mV��i|~�|���M���1���n���W�������dO�W�y�}y���(�8��}������z�]t�>�`-A
(�V�(;�����A
[)p� E��>��
7I'����
��|b@=�g����B�v*M~���m������6��Y������H��+�b2��C��J��,`�Q�_N(9����R��V�0�!l2` �2q�����Sr�?<�=����x��M��<�y���������aX��I�H!�ZIo�O�H1���8����^�������C�:~{
2�/���P?Y2 ��pS[.��$�����p�J�k�:{G*� �:������#U�Xv��S��j�����#�xk�JW���=��f�>����	��qr�����8�DE�W�yzxy9\'Q?�8��j�F������+<�l�<=��f"����������n;�����a�{W8��Kh���d���3����5p�n�Wx_
��!t�q��|���k�������Up�d�~ U�Y�
�d��E�}����dh:?�/�������!��jn�\7\&�g�4N��E��i'0�I���!��X�
L���0`�HQ
20}4�1��|&�Cxy������6��K�r����+�'��W������~���4Q��>�t?��N��qv�����8*�y�
���J8���%���dW��]�����d+�!��v�}=��.�
�a�w:���/��k���Y��}����eq<�|�U:����p!z�-D_���7�W<��A���GE�����n*���	�>��=��Lx�����/z�)N�zQ����~��x�1�IFP�b�E�������l�p*�H5��$c�G��(�j"���W.Jr�.;�+�n�uj,L��{�����������r�7G���/cp������Bo'��y����[�dL�'�n$O����������Ch�qV�S���6���p�����|�i�"J�������3��H�~/1��It��5����OEnL��f����$��������9V���9C1��\d��5(iG`�hs���7�I-��o"R�O���4J�,���F�V�l��3'���C�x���<my��U�'�)C�C�J�9�u(��B3�< =��HZds3T7����#-U/�������\
���`e0.;�B���������k�2:N���Z=�ZM_��b�fyB��X �t
s[o��)\�R'^�X[���y��]H�����\0H��TV9��*�+�`�hC�������#EX�0"��#l
Bl8���Y�3�B!:�s���)�	o�(�=�!}��d�Y����������HM.�)�2CD2�9fm�71�����4]'��$����>�U.6)�'����YM���4K E0��t�E�;2��-f��!�ah�y����	��(�2��!���.��?�����?Ax���W����\H-v-P�>��w��r.�T�����=���3�/~^�N�����f����� 5p����J��}?���8@�aG��Mj�i��8/L��8��s���
�� �$��Fk�5��T&�����[�������>��n%����_7dm�4��S�0�S�Be�����hX�
�Fd&�T�C������B�����s:�/����m�%3�����D����B�R�����4������e{���(?��:�K�����T'l�fh�z�#��5�����X�������4+��,�v; �����Lg��
|�}x��G�Y'2(�#�qz�R�J�O'�E+����Y��[�I[U���:8�����=.���}��AJM�e$+� ���w2A��0$�z2<�u=�CzTw��6�Zz���1���:���\:��GO���WC��C�����)*���I��[0����B��7��D�8�D%�]c�t��,��y�p���?XA�=2�B�1����>���$%*�l�eHr�T������*S���n��X��H��2,�W��5�[�9��p��5h	�AI�3�F�%��=5���Z����G?�A�0���o�?��_��#�o��&������o��_]�B���A����[�A�W��<��L�j
����e���v��)U�Y���rufC�5�*����_	���O(�������)�������9�� �+���}Fw�.j��Z�.B�1��T:"f
m�Fu��WHAIZ�KY9t[7���� ����nM��K���a�B�\EV�
$���o��;���@p��?�y.J�n
��e����B�t�v"�NM{xG�	�}`�f��;xP���f�j�CQ3��t��K��������iaaKQQ�'���$��1����A�4��U�����p�To���a�R�����W7�	+��t�����7O�2`���ej�H�1@���h����t�)�n!�Eg�!��a�_��s�������	<���^��5�em��\9@j{S�o��x5
C����";u|���t���o�"z����DY����GDA�vabc$�w�C�#F�a����F�e>�f��;y��*8������s�����K�4d!�]v�O������������z,��1���4�Q��%�� .�p�>K`U�1��x�N��H�z������
��y��LN(YzNT_��Up����d�����~�4;�d�]�S)������1�dd���/�0���l�P�3�2��Bxv��8m����i�������)W��, �P+C����tf�2��=�Roz�,b^���Z�(<���|��f�����b@5��!�*�]S��f=&_�M�S���t��KT���J+����BF��%��T&���&L�<g�[m�20�[��	#��Z�?�Ucz6t���?G��D_-U
T���7����F��K��LU�U����Z_P�~�9�U�[�W2�����E�6�3��p�jW*����E���ey��/���B)l�#���Q	d��h��eo>1|����-$O1njz)\����1Pp�if[~��p��p�E���ut1F��'Q,���&^��������G�nlR���S�23t ���
|����~-h������#��3��W�7�	&#@����G1U���k��%�&c��a]���K2$�
7? ]d����x���`��V},2��|kZa&Q��s�Sz�
w}��d���!�M�@�O����x�P��jDJ�����ok����5��8oY��Gc�\x$,��B��,�O;k�R~
�����"�C��Wel����L|�a&����t�&�9c���
��9�,�y*�d�����MXs���C�{��z����P�!�E`9x��'5	e&���KY0\�=h�����F���0~�,
���h8�����Y���lY#����WA�42�P����L�
��oxp�	��/!���X��aJ���k
vnj���X ���]F�l�d�#��4���+�" ���Su���������#���
��
'{	��4����U~��Y��1�J9����I�dw�`�\N��.��^���|�k5�<�^�"(h��u����~o�9��i�U�
\]2N�����7`WdI����1��c5�xEk�d���L���!A�4��R��
Cy������~m���{*,�����oK���z��7��P�i���1pH�����I��;!������N�v��[�^��i��,*#�$��0=��!N���f:�b�]���U�i�M#�O��F �����TVv�\$�`�t���t@������N�w�P5$��:�+��u������0����k���X�w�����pch����ARd���!��Yd����3�}3&d �D&�M@GJ�������>�3����n�L2��(�+0H��:������J1, �G�Y��%��K����6\TPOT����
)f�%�,]O�s�_�e)��1~�F��q�,��%�FG�<��W���~T ��w~�c�j�U� \[@��(����PU�5|}�Jg��X�
]M2�<���T�=5�4���0L���,��F0��{.J������ ��b�=���`"��,�`XXW+Y(��C	V���@��c�K(Z�s����h)��F�cH�
�
B�I�YO��P�xB�
C�5�z���W����������7~��4C��d��Kj�482(���l�`��3;3�QX������5��[`���|/�n����h�Y����x(��l0��X8*��a�z3����^E�w�0�!h�i@��m���+�v��t)I��r�����-PE5��*�������L�{�r
qQFe/��.>!����#�&ko�/��x�kC#HI��>� F���Yj>PO�O�����O?E�~D�A��N�)��@K�m���-��*S:��L@B��2F>�=������uA�_����8H�^��?8��h����=|��]@��o�W�{��W*@��b���1j�p~�2�a��������G+`�-,����)74��K�1=�����OM���J�J�������������w��E<.�(���n���f�NDEJ�6��������zN�\��=���*`
����o}�vj�	�&.\dC����:�*�.�f�G�-N�����6�C�ix�qV�S\<M}��$�Q!f�P���p@�t�v\���������)(�������IaA�3*Z)�]w����g��l��b���s��'F�	�������i:OD�T�:�U�!iU��(Z�P�8��81��r���P�@8���N�FB`�����^$&�x8N^�6�CGq���!.4�AG�(����O������A&�D�anG���0�������7�XG��~�U2��������7p�������C��fG��XE������NY@��v���a�Wu��Zm�XPv�9.DQ�Q3���2:U���hL���&��m�U����@����q�^�/d�
/�x�b�R<�AFUe��&�hm2�<69�����=I'��ld�������2
���>�^�����$������L�3���h�NT��N�l�
����*m1����'�U��N3����-}�>�[�-{��!��d��%K�{��fd�'DF���X�W�"M�A��@���u�����w��6���D����<�Q���4!=�(�a�����^"DG��|�	T}�2����A�1ot=b5�c`9{�ed(�/v4ZMO��-W�H�ZM�z�������U��v����i���)On����!}^���O�_xB��UF���Q���}�
�;H��.�U���������`�A���M���]���(~�XV����)X� 2g-�0���Md�h�}�R!�d��6�w�k�.�3�_���6aAGRI�������a�9�U�B���c�z:$wW�9������8O��������O��q^�w�>�������=�[�� (<f~�t��5rf�du����q�d�Dn/���Fu����f`���ni���5��:�����V�.�Aa��&���C�2����|��~�CV����u�pI����7y�2�kZ��:]�8����C��j=-LG����Q�c�l$�tw�0v������h���w%�T��NE��|g���}����E�|��S���h?>��/I�K���'�=d��p�T�s{��!N�����W��?=?_�w=�/�k������i�S���?���//�+�����@�y����gE��o�x>������~��n������������e{_Y�����z3�<�y��t ���"�xJT��P���@y�
s&
�{��������n�uY8��0%�> u�L���';���E���S�� -��1PG�������Me'u\n���0n2�f�}������(*_���x4�, �@%i�V���QT������������K2x��tE��ah'�2��iE�$���@lOt,���oF�.	,��o�����68d�u�������,K���z0�=-�@
������O�X�����Zc3&����2��$����������������~��L8/��e���8w��}f��F�����9�t�JE��1fN��Q���(�/X��q�UM��a��*��.G��c�	^���
�����M�`'�6��>���g�Z������1q�<�'}<����\��o�3�E����-������>p��&J�)��S�a-Uh�E��T{��[�A�?��?���n~E�n����_o��S��H��<�|����;�[�����q����o������N���xI�;�����u�:~s���N}�����.Ko�z�-K��_�{�
���m�����\����|���������������&�y�8���;��{�3��?3PV����u������i[g�#�ue�	�l*��{@�������7h	��9?��
�S�ZSO�F���3��������'�Cv��;�����nN�G�[L�=�[�"��q�S�n�)������;���v�X����b��PQ��������2��y���~�q�,BwH��,��������c,�k��.{Cgq��wn�;�x����~��ot�1i��/�u����~�4����^�2���"�<���&����nX�����4�g��,��y����%'������q5S�v�gT4���� k�~W� �scD;[^�o����\�v����=��VH`u7�3�R���Wg�ZFK,����:P�1
N����������q��-����������~/��z2�Zlz���B�6�P��@f�	'u�%E��V����p@���v�z*���*��\Q�;����R���@�Y�~�������0u;p��Y�Z�@�z=������)jm���q8�P}�+��px�p@V���K�d>��"���������)Lsv��%��Up�����O�4�-�am4�h��X���.O������oGv_/�s+�2�l���=���g�j��t��V��Z����_�i��M2��/r������H�C�6s�tSo�S��L�5���r�]+�����������a})���s��t>����7���9��eK�@�Ec8kC��G���5U�0����wV�:����(�s%C�[��gKb8��T
��b��k����8_3���+'�W.L��8���6&�Z���%�w�7�Z��1��U���g~S�t>nH�_u���7��d�wA�e>-��g�L���-9����Z@���$�x'|*XZ�l�Eu/:�u1�?�i��oG%�h:��_9xu�*E������;�n/;$|�@�d�dEUKa���R�����$\q���R��(j�mG���M��8XXN����^P�<"@w���e�A��jc��� ����k����uX�2��c
M	��QFDuaXC��@�xN&����s���S�o\�!�'�s
��$4�A;{�Nu����qV����������c����Nt/��������:�y���������\���W�G�:M�/c��+���Nz�|
5o�vC�mA]L��K�t��x�m���x��	��G�[W��p�q�+��2��=$���	�2].d]�XT��F�A������&�v����_?5N�e���nle�2^KZ����~�Nm�P����l��UE����T���rf���4�����U��W�����xz?2�.��E5-�1{V������%9�������!=o�������@g�����;��
�+�1\Q+}�qZ:���E��s�[�{Sn�=TW�����T�u�����v��f��K,�g�0v�����`���8�V�K��J=P�siY������������E���
��X�;�T{_�NG�=TN�����m����N�p
Y���}�QZvY�.�qZ@�`Bg�����������m���snh"I�G�=�=+87�z���j���e����y�s���0��Z[�B@��<���������V�^��,��'T
��Ts�h��+���+^��8 _e�K�R���fI���V\��N��8�\�:#=���,�u��w�>�t������M���h�Fqzo�\{�de+:���
��B/���5������xR�E��EP���������
F0Nh�0Cs(�Xb^W�uu�������Z��L��L�t�)��a����?����I	f��n�/��9
��f�!#/u�x��EY��T�S7�A��E�����h�K�g�w���:t1��]]����w]�<�����ES���p�����HkT���������O+�h^gj��F�;pl�v�r��e�T�)\���W�[5��M��3����S�!T�m���������"z��)2��k����H��lG]��T��B)�!]O�?\u+�2J����C���-�����U�t*�PgpisG��
G��>j|� ��y}{��"��M���
oG�7�<����;
�=���F�t���L0�T�S���8�I�rR�5��R�b�\�d)u���)�hAm��5L��;�k�*�������u*��8wg=��T��(�����>F�z��ig���r��N�5b^(7D�n��lw�����t�5<�:����A���Q��-p���5���w"��(��^.x2�J�y���,B�G��&��	���s^�e�������b�'������}��=p
m:5T{�:�!>�K���x��W��������iv�:7 {th*�������������,�p�oh����"��o���O���T<'��t��2���f���*��$��������=!B���p��;L]�e��������l��
�?���U�$�x�]����y��"=gf��sy&�������z�YjnH_*������=b���r��
��~���Em��J�v��$�,~Y���W���=��{k�i:�
>��$���(���c�.��*_�tr^�u�����kGmU�Z{�Q�<LsDf�Ny�7����b�Z	a(V����,(��V�#�/L����	�b�;�����5��0q�������W@�����6��&"��Z�z�����F������,1p'����S������ ��TE";�V���<������	����gd1{������S����0�
|���a��3���\K�����)kZ��j�h	�j]I���m�xq�6?��uN���p���0��r�������Kb�1��-��n���y�P�-��hw��
�����yQ�s}QwH�l���3G�8�m"���E7��BW���;���;�>��C[���{�%�e*xy��=��-��n��Q��+a^��R^����e��P_�D�J`��)N�l�.$B��6Ar��|5:���'�p����3��|���j�
g��0�+��\^
;D}f��0���J����`���VyM\4����8��/���d�/�:`�.F
%Q�(��"gu���7�����dD%���*R�t+$.u�,����H��X��2\b��s�hI������>Li��$�;
�e�	1I��������T�"!(S�v��t�m����.��O�T��-*
����q��H�>��q��l����[�*�mu^�m8Q���g�ak�����[kf�gsgz�
b��SbGc�����3�\��E=�����b �����_�S�^�s�s��E�~]Td�VS�[��d'z���8T ��S���|��`�#�1��G������?��b�V�
\��[��x$������P�E�8raP<�6�Bg��I�y�wC,`���
�M�1�4�
��}N�[*�s�q*_n�����e��c8�>��w�	���K�s��7����sE�w��1Ar��������"5f��d,<���Jz��'��\v���k5���ol�L���lui&���7L���(�������������I�8����#�s-�>:T=��y���kQ�|����QV����p*�����}G��U6m�c@� w��q6���b���<�?M������F��z��$�
�����2�;��8_����4��)z�����iPe�`�g�)��L��j_����w�� E��G]R�XG�2cg�%�5����,��������--��A�Av��������lD}�����Z��/T/��:H��BN����	�sh������?Z*Q��Z�+mVe`T'�9�N%��B��-�m�9kd�J��AJ�����jM!,�A����+_�A������z���*��Go�&��(VOD���m^��D�.��,�]�N�����������s:|�M.#+��D6T��]`�uH�\IP�<^K�~1�6���B��)���pu�?;5������K^��������:�.����x8X�I�����"�:E�M���s]����2�Ix�$���*��IE��I��$���S<V�9��kq���?	�	FS�����rBSV��sJaGx�2���}I�g�$���YjLH��{�:����`~��\����eW��Kb>|��
$fo�\���@�Qh�����C}s"������u&�?G;SXL�>�6�+�e`�9��/9�UT4�K�����@lC{&�3
�}�t������t#i����%�V����7��9��s��������[,��@RV����VJ�B��h�\��^��K,�������K����3�[R���	.���;g(������^�w�eb��������l���DK�4�T�x'��/La�yU��E�E�B�t����2�������\�'��c���&1���.�P�d��|��%]����0k��&{�y���}�k�jK�	.b���������X�P��V�P3e�2#x(g����dd���DF�7�X`>���fy&,;u��C�)vjQk�p�P�O����!A���!��!�C�`��m��r��PMck�v����i�AZj]�%�p��OW���������*�^2��x���Q�j�	;n�	�� �e�Lq������d�7D���Z����D��B�����c�F~t{n�O��[������[����-%<Z��8��.�;�C��DB����] �0%�����a�4��nNl�xR����X�u�$>�2:pz���O���5%s�\J�XV�1�GTY<����}���&�@������6
p�_4�������S0��Z����*!x��'��`�O&�S78�����"�'����;�Y��[��r8H�0�i$Z� �R����RmF���:t}��@����4��u3*~���A��c^Lq����XI:\a*����\��O�f�\��4my<��e���^�rW�Z�n���6��>�Wd���b���K��e��v"�-��~pyJ��Z�$�){O2)g�S��?PLkVr��;��U�]&��3��v��F����(^����{����u��9d�������G�2�L��|0���[g����
)��j�)M���
 �'ZZm����0$i)�k�4�v?�Z�H�����t��P����yS]u"��y$V�q�I�3��
I�,�Z�zt=*��Y^�����.����?���El�����Jm�(5��~�/����_a�`��8��3E�CK�����V�����f\T�zk�%=D�xau����yBB�\��X� ���}������H,�b�|�����"D���I)����?�$ ���@Z��:Bb
��6j�q����L��{2��L�*4Q
�n��/J��ER�<�)���t
d�M�)��������	�pM�@uJ1H���!e�&F�����vVxQC�z	L
�
Yrw;���*aUv��X�P+ze���}��q��.�!<�`;$�x�)�N������_`bJ<�E|�7�wP�&(;s=�%��pC���`��b�����!��Y�-SQ�����v� R��uB}rV��������S��Gn	
:���|.�cH
I6�/��lRu]�wtn�#���
�{��i���+�*���02�A����x�r�'��%��>wtK�]:��41�<��4�:�5��:��rl�o����\������^o�
"l�R�������w���s��0z��D�'F8R��BL9%;i�����K
���m9���C��������pY(#������Y�c) �_��[���*`��&K2���U�<�F&�)��Q���CD@,x����j=��l�v��/e��S 
��
�B�V���������UX��!������<��j�h�)*5�)�0��3.���S���x�RGK���s,�2Z���~!\�g�<(Ey�z���S��BR�2G�Rs������v}�H����m���������L�DA��s"��:�H�ezDvp��<	mS@+�}�X�,s�\��5s�da�4��Q������%��*��oP����!y�I��<����f1z�S���s�?�a�cP*��\�/I�F��������V�T:�2d�gV�h����h�6����B	Z;�����.��I.�{r>��5�?����ip.a�����8�o,�����n��%!IB�����S�G�Y�cI���V�bO�y��I��&IQ�"�%����=��X������b��n���0By�E+5J3Iw,s&����6���<�{����Ky�|9b.|n�8.8u�����D�"}�f�� Hc}�%x�\2D�s���
KI�����b������Eh�2�{V,���==,h{'IGa5^v��^T&�\�F��m�[�����$s��Ufi�A�0�\2^��v�����{=��������gF��J�N�;�+5���.?fyx�i5����������)[��/�0��q��ovX<�T�����
R@�T=i
Z}v���	VDc�x�*��Y\EGE�-���S1�B;�	/HS-	K;��k�������
X[Vy�1�J`���H �
'�z����PRum!����(���7�	����y��,0��fWR����2����Nt}]B��{C��]~c1(.E�qu���Q>�-z�T��)�g�}��z�����{r��i`�6������(?&���v��V�G�1s��A���g�0c_� �p�[������&G��3��\'E��������Dg_'�����\��u����X������B5�8��!����F)1|�����{�2B�t�M�x������6~�����O��*�xsr���i��������Kv����<TJ5������R������p6h%gQ�[$��dn�������v�ydA����������������}����k&o�,��9�����Ytm>��<�3:�>'�C�X���[@;�ou�K��sV6l,�� A�G�\LL��Njk��AK�I��p����Z�f�I�+���o�B�
�9����u,��$�P���A�E�.��s�Y��#p�� ���`�,��6�p�`Q�t?��V���mv��v��XF���{+�cmz���8��U
�t�6��YD�2Z��co�aW�8����������@u���{�J�*�g���AWG��%q����l�ih������|�b�	��R|er+��d@��%#��}\!��R��6J�]7���Z��:���E��qxd�[��<(Jn&�PV���u�q0�!�MkS�K,h����dO�K9i�%.���V!���ThJ9�"!��F���:$?����i*9�m,�o�����?��sm��9//g�@�5�c	e�
����n����I��q���./F,DW����~�,c*;/<��v7�f<��E��FN�ZB����������x���
mN�<�^����'Pj���&�F�����M��#�bM�!��}R��edGC�X<�3T�UQ�a�b���n6��b����V���68E>6w8r5d��$em�����#_�����`0�c��J��d�a�%v����D���=rP�<a!�h,O�7��-��{t����CHt�D������~�v�;!�e�
�)�4Q��F�F[bI�"��t�����aw���'m]�(�tt!��c
��Z�pg2��C��65\��h�LxGo���)������TAW�L^b�&{G��4�F�����)U*��m�8AF���Y�QPu��1�b^�^3[�	�o�G��4C�8�D����:�����&�|V,Ye<�9�Ww��Nt�����'�J��^����8��8�tC�~�,�q�������H��������=%`��nm'��k;��#0�'_.���PE��E�.V���T\�[��M���5�����=�+�@�"/o�sq�W�s�"1��4��I�./�T��=�� ��/K��4���co�!�Z
~~j��������������H��53�}p��;
-pd���_~Ck��;����/v��UtuY�
��h	������e	-���m,��m��`=\g������m��$�Y0��l2b!��FU-j[�z�",��
��zI�����g�����!l�/W8�������>S�k�����Z,����e������N������8���p��) ��r�v���-lg-�KT��b���J�fp{�"�����D�B2��<�R�f:�H�>���Mz�5���:��XO;'�h�V�j0���9�@P����]��+v�S�lc��SO�1~6�)>��'�]�����>%C!�e���P��#Q\�:�:�H��B��^����/�|��cF�0�o�+�w�~�D����e����O�@@rF�?,����,�2���5h����&u;�������J��V�
��IX��PM:�������P��2o�p�N�T�2��cQ���t�H���y4�\��K������X��V7c��u	0�Y������_�+!�nC2^���	���,G��X��Id	��"?Na;$G���f:W�$��j�u<���P�������K."��?�Ts�$��z�Vu[4S�R�����?R{��S�$������
]�t����snCl��o��,Nv��f�����U�q���H��U��T��-l'��^I_��%�Z��-"�����DvL��nu?�uWC6�g���xV��*�/}��Xj_��px����^�O,X������v�����p�Q �[,k�~{�0K41T.��+N�������B%ajc!���y(ZB�@��fD5F7Tm���or>6I<�]@_���1�u�B��c��5K�S�&V��$#|�G�A�^�`����h�/�65��8���&�����q��p��I����3| &���R�<26�CF!�����D�"�������J~3��>�m����U^��L
��UW�f�V�����c-4�\3��(�/��M�)w(>;��f4���y�>2*#`Y�]�oW��c\�oE��>���t����A`(:��Q��y�6�d�,�G����#9]p7��z���l8��Pv������u���9NT�4�x
x�P�.')M�
u���
���<&R7�J)�$H��#/t��h�f�����������:���H��X`��|_0\}���9CC��`���rp�	����&W�zhA����k�}�U�����_��%Q�#	R�q��dV��F�
#���������q*�� ��a5!&c_��8����U��M���������H0]�����
�r��t�����r<�����+_���P��AJ!.Y$�B{%�S��gUYY��`��F�@g@'g��XT����HS��"��X�Q�-�o#���*x���t"��1�g'�������,�*��M]�S��R�))��M�[��X|�|ISY u.��$�1��~�Fly��D�n0Z����8.��M��J,WiV��U@��9ca�Z�C��.�K�GB}�%�fG�H`X��	8"����O���l�4�R�U�����E�`�G��UjZt�V�7�c���
#ORs��-����2�7�k��\�lE4���?e�zO��
&��-��;�$�Z����$�Mu�s�]d�L�YD�f�8*��TI5�6E��R�!���v:<�O-�t#���@kF�Z�L���N$������������~({���5��]�)>�;U��u���dv���N�8�9,T�w
{2��L��%W�@��B���A2oE65hs;��|������h����������>R��U�!N\����_���^�����UB��b��Xt1� �7(�a���x�g3�{}*Vm���.v�P:��\-�@�H����[��=Xg�A02.\��������_;�1����5��(cUe��\C�q�?��U��-������i,��
��WbQ,^W���`��3z�\��t����z`��#
�����%q����V�h#� ��<���
`�����w����x���o���7��@*���a�����;��z��X5��K-B���P)��@�+V��7�\��h���������6�>Z`3%��wve��x����#����*��p7�%g��~��NcQ�Lj,�g��Hl�x�U���s|��c�,<��%1���c��,D<S�M�Vs�����T4v@c�`k�[
�Z5����| ���k�*{��Y��Y����!m�E���b��.��ni��������pF�@��C��@,�/i���ae�����V����N����4�H�y&���E�FI����b�x6*,��0��QDj�K�����0T],dj�)�5�"^k��������r�����pE\h�~��z�	D���{A��FU�r���@��^��-��"�r��{�3�3�!0�M,���RXX�{$^*�
�T�l�G������I_H�:o���`�3_Eu���L����z�,�c���|a���|��w��L���#,��s�R}����9������x!���_$�E� Hb��F�h<���A���U���hX�^GD��+������0:�h�@�|<�G��"���I*�r�������;�W�N�	H��K,I��j[F7�\��9���~�5����Yc�X���j�~<����C��rS5)�"9���2�q�eS<�Dx���,�VL�iW@���PD.��|xU]���hy�\g����Z��K��$*��Ek�}N�Bnq2�����b��������(&1L�A	
�VB[b�,�0��+|
���o�����Qyq�����.�p,���/��O?�j�m�0%;GW6CX������[�����Z-L�K�d9��D������"B�4K���U�6�
^MW��B�����s,�yy��)_��Z,��Y<���G�tU��G�\���u5����ZV���6�����k�����<�k,��|�D����W�O����A�i����"H�.���^������gA�A_Z���_�������~{�l�"p�MGi��	�}����I^�&��>����gv$�I�H4&����gM��$�(�!���8cv���d5���	�H?�"a�Q^�L���E|5������z��e|X��������2��1D$]���{�1e���E���x�����A��(��"P��XM[��Gl {���!�����h�������c�[�((�<�����`�� Q�
_K�'��}T	I+)E]���2�	L���b�@���t�7��.d��a���0��[m�INu�dE��Y(�t�S�xT�ud38�:,:Rd��zM��O`�U#L�c�YS��B������Ap��h���T�^N����:$�}��Rw������b�4�;�z��.!����vF~�a�9C	G,dA�*�M�}�y���o��sX����*���^/F^Op��A�:>��d��x��f`�=o�2	�h^xB�l��e��3w���VrJ�����	��.BN��PZt�~&�-$�!arb�O�9��Wk�R�����3"y���R���u6�j�/C
Fv��^��������}����c*����J�h�t$D;��,
�vA��'�Vc[6�H�h4�����S�`@�4���H�8�*9xK$C�6}���"Z���Ec
{=����6�l� Y����b���UZW�*�,�A�*��1���)�h0��t=�:����i�����LF�$+���or8G^,V]HhF����D���R������'��������z1�&�)��� NC�]���9�s��A�7��z����@f�"q�kJ+��?�=�Z���TTn> ���9��BaN�R|��/�����C���!g1������`�8��g<
�F����MlS�^|��0����jv�%�u,�<	5�,�d��ZI��R��T�{��E(
$���<�F9�*,~�>��v�}/��K.��'��.'�p�4)
C���\��0y��4}]T
e9�"s��8�~���& O�Q��&6�0S�srx�_�f��I��=L�*���;���Y�{GH}��0��}j��Q�x��\��~��������h{M�F�������E9M��rU�d�v��B��_����0.��YPvw�_	��S&i6����B3h,���j�u?��5��a�8S�=�W�C���7��(��"��"�y���l&��K���S��	�m����i��2�Y���zln�Ve%�Y-p�����r���*!��}R�>�eL4\���(��N���1e�6$�S�=�&@��x-o��GB��-������P$dA�$��aZ.�
�v@�F�����Bh����r"�`WE�Gk���\%a5�4�
y������a��/����V�4%���]V �x�
x,��7��-�
�j��>�1�Ky���r�D����{O�:d��/��y!�V��.0
������Zl��.���������
��]���\��-f��/��Hn�L�-�|���n��A��O�~Re�f����h(V7$,������*`K�(\ �����9�C��"��;\5�t>�#�U����_	Y2��P���Ze{�(nZI����)���S��r(
C����_�d��C���)8��� �-}��/�e>����Q����
:��Ja]���P�sh�&�m"#��]���F�g���{����U�3����Z�(�����������"���Dl�m2��K�7��~��=N��v���t<�j��@�r���J����I�GAp�`2^;�f��E��>���e�0D+oR.���{u)��7�o�t����H!��2��
�:�����2��w7AJ��y�%.���Y-���4C?��= ��Q��dj�A���8�.�B�u�[?����T�nE\Y�w��v��]�	e��:4��	L�^��*e�~������q�S.~HK�y�4�.��	C�~;�[����h��bNq���
�]�~i���N�,T,����G�������pi���y��&����jE�����&�S^�$�lJQ|.�mH,��faz��o�|�����[\ +#��A��&�� LJ�<0l9�)��:`��#9��za�`�OA����o�/�#H�
qW�&W�X�K�����Gj�X���TG�����L�����\&�:MJ�9�f�Qr����rlP�<�#?b(���%�s�����1+vB,0����c��Ir�����q~!E
��e&���~M���t�Bo8� �$�o/����2��(��
H���/���7m�,��$�BM���H���Q����D,����c��������YHRlN�+`�^�|�H�8����r��O�_
l��wr-l���R��n_$/Y��P`��!���P��{�v��o�f#������k�U�`�#���n�{�\W$D���oE��H�e
�D��y���x���u��������9sf���Ze�0�{_���q��9,�����^c+89�~�(e5,�ZT���t��:�X;����E�����Y@Ar1*&�Y���=�#��IQ��"��Er
�g:c�b�=:+S���H�`��I�Pp>kv�2���,��\�����A@���c�>x�d33�^�a��`��~2��J��J|`f�O�����H8�D�hH��`�Y"���H�1r��n�,��� ��`]���h-y<�����!��u\f]��V>�
��������
j�z� �%��N�k4V�������r��U`�v���J�y���(�E?�G�MT�`1��r].�,�j�V�����3�D�p��c�0:��v����Zc�e��j��D�iun,��K�����77���f�n=,
BO��t�k�������}Z�8M0 Q��{)��y�*pJ�[�������d!pD+�
��Z����|�B��Yi��X���,��>8���6P�o�X��
(b�"ugB��;����cU=���:����������\*�(����4�{�d�#��D�:^���� ���K��o0[/@4��X6��1��������bQ����F��HQ�y�D5ViVu�[��K��!q���)8-��JR���J����S�6��l���p�m~��%�>��������hI���ErR�8���`c�c|K%�VJ���xY��� .�$,���K�tL��C[�`.1H~jy;���0y�#BuSh-;)x���M�e]=T���l1]���R�|j#��##O%�xI���JzXG�D��������(,��������E����� ��6�M(f~�����s�	�����\C���������^��Bv^�V��Kr���/�/���Y>
��3{�������.�}�bJ��h��P�u�������z����$����y,��q�$����F9O�&�EA�7�1��]��$*��cv*��
��%��,��o��������"�o��,@���7������ Yc1|�z�F�0�(XezYPf'z����i_�k�.A-����H1b��L����,�CZ�i���u�����L+6����T��M����3>~�������/�2��p����]�����������'���O���7R����i�����\��l�O���F��_^��8��~�/��������6K��r��%��W�c]����/����?����W��������#!��Q��_�����(E��^��A�;��~����x�g���BU�D���?�J�?�(��]�g�i����aw�����?���<����8t���8bT����JY��.w���]�m�'���>�����o>�����}�X<n�:���;~Y�Gm�c������G�,A���.|����)���|�,�u-�������<dV���������D���.Ak�����i��{��)������2�k���o��|����sRr��?C\��^��������6�)=S��I�EE����H���^4?��	(dbq��a*M��������,�������)�����/�����?�G�������w��j�9�������������������A���V�����v{�m�6����������~��������*���g�����4~-R����s����������?���{}�]S�w�9�+�X��#�p����F6Z���������������nt.��0,@�{0�{���9�{�o����q��r�����*�^1�����p��V^`����x��gi��E`,9�3a������p"6��m��o	y����	�3;��T����Id1��C[��|���wz;
���F�����E�>�m��dE�xe�Y�<<w�w/@�R�R0QNb�����O�����=��QF��@l���2�6JZ�e���d�����v�
���ln���4+��Y�D��+��e�����JG����}�?< Lcw�����W��
���i������z���b�4�]���-
���x��>��#
H��Hi��:C*=����������}yY�,�t��v�;���� [m�%��r������kT@'�M��,�T����^����L��[�[�tr���_�z�1��T��l�c���{������a����3�E���6O4��d�T��;�Fr����h!|q��$��
qv������E���
w9"g��-��y�Y�6��j�^l���yU��9�}��E����w�G��;o�}��*���7f�g�r�����D�5O�o*�L���<k;.`�����H�3���~$����"l�F��}#���C5�T��Q"B��qI=~@�~�<��=q�����B�������7��^���o�y�-��1�p/}7d<���fv�A�3W�'B��E.�����5��&�k�3��D�N�
-^&�v����3������}cI~"n�����i��_�Na�r�X���#*j�<h����=��v�;R��O�)O"�\_,�����9=��n����_2��8D���cG7�$����@�+S(���v���QQ)C���49���f�J�1CD���m	�~���>k�X��=f��� �6L"�(��!B%���=B1l&�������}"���h���8��fLU��j��!
N��]Y����mL|vOr"FR�|oFw��f|����:\��pD�Lj��������!�G����E�T�G��[�#{���
������1�r��$��uk'W;t�]j��<Q�72�~2�Un���}�[�'c������"3�"e����@��������|_���o�ZX�����f��$���I�<��|.BD��z^M*@Tq����c���j��������7��7����,I}ifd������o'|����>i^���X%��>����x������q��+=CJ�}���A����������A�P'��/���e�j-�wz����	�V��bdye�K%bL�odP$U�����i����t��������|��������8���U�N���}X��p�(���^�����%�AIa������{CR�c�q�cIG��8,���(6M���u]@��T�"O�?}���{G����i@���S+�hV��n��x|
:Y�y�I���hP���=p���������.���E4�E������)�k�n��v�.D$�(<'���������E������������Z��3��>���x����Vw���h2��1�4*&��arb4C3�.:i���S^+g��<�bQ�9����z����+���?�N(F� ��w,z6J4�������J��_��3D�0��b�c�WZ]�u�����\eiY�N�NF�q�Q%	d%J�-�0��_���V��
-_#��-�gV�#I�z}��b�^!��<F�#��0�.FK~��������(��-�������j�_�����<�����t���=ec��f��+���������@�-�}y��c5��Vm4��'���l�o�&AFj�U�K?��������*�;�E��za)E���iq(ZhOr����1-�<s�^�"O��q��F=U�i��&���f�o��h0��~��f���#�U-��7�&�����hq��&~����V��$�h�Z�-cz��mVBo���x|���WH��*#M3K���E�u��p��#�C
����49%ab��0��MH�"U�0 �����S?�T��Z��oNA{��B�8�h�C�8�;�����%�#���
y��D�����i)`!�g6h�v[Y�y
c�-�S���l���������[z����g��(�%���6�5�^ *
�B��i��1�D�����_�kZ����O����#7�):l�.P��:q#��$�������.�_J]�wF�1�P1��(��U�&����'F��mIP�!]<"����!�����^��������c$~����l���e�������R+b�x
�X3.����hH�$O����J<��-)��"�k0��I#��?�T9d����!��F�dW���yp�����R+��xT�g|=�J�5�2��U�Y��f������o_�-p������Ph7���abWS!��v���Z�y�H/(��~Nz�
N��5�XS}���w����*�����������#��L}�����2�w�D�p{a��:��Q
��Bd��9]S��q������6"�����N�����}��DOJ�d=$��g�E%�=5�O�AF�{)_o#��-zA�������r��kP��3)���������)�� &��M�R�����^/�	i�M���w��p�(�3h'�t�������jGq��|��z����yG�+_%��?U�_��&F��X������.��[.�+������p�y�j�0�q ��QXU3H�7;�j#����C�Bx������_g�
���
�
�[�	%��;�rb<�W�xq��I���k���z���(�-���e�Y� ���s����(/�SL�fM�f��*i0!��%�5V�A��]FL�v��NR���sV���$x/���{�_2�	���"<��h8K�v��BY@����� ��z(i���Q7�<,=R�������V
8�A�n[L�
� ��|��D@��H����x���D�+ZU���"�;�Rf=~o�0���M��/�����q��hYT�h��Uzt�'b��G�n�*����-a
�kG/w���/�e�����ek����w�6f��� �����d	}(%�U)V��9�q�B�*"��E�@�A��������&����M��\w�}����x[fm"����=�`�4� �������X���v�%����U����E��&��>�N��C=<�7��?�&B	@���S�1/u�"c���fNg.5�x��m���.*|�J1?�s7)d3mUC8��"~-��,����7��?%�O�eadi�4��\e����������o�9�+���|+j|d��_[�I���5�*�����;D=���q\M ��l��U�Mr�=��\9^/�^�X�pUF{�}/2K�3�4s��*��c�G�p\�5�#*^�a�H�$�����g����<OH	���/���Jr3>�M��'����5���������9���s�qqZ�P)V:�������=��������R)��}�a�`KNZz���F�`�L���44a��T��a:=��� �0h�Ju�� <�*��B��?��.�Mu6�����~����
/���=r��z��&#L���|N�&��{V�Mi�����W��pyW�}��t�������D�Mw�b����s@nq��4�"Vc{�i�S��
4aq���G|,��:��|x~�s+���l�/��c]���J�?it��u��yC��dO[�q�?���L�rt�h������tGn�'����z�P;vUr
�~X�H��3���fI��m�'Gym-E�2 Q����/J��$�����o$y����#�Q'�z��)��� ����E���v�J�/�rd�\3hb�����V;��t����������������4����R�]��Cs��u����3Y��Ne'uF���+�����k���:>r?��	��^�H" �����1k�]!��m�����Px@p�UD��,�E�p�����������+2s��E|�'gu�{<(����.��_�����x9��Xp�=@��s�6���GC%���Q��%�xa
��-T��������Z��9���Q6f@&�����Sn'=x��f��F�w������;��`]���T�D�87����5�i;+aU�Wk�T�E�](�d��?N�tZ�J��e5uWHSb#��v��N<s�
q����hlrkv�8
���J�������JI��J��j&1K�4<�Q�u����)��m�jR\�c3����6Y�
��8����<OO{�tJvSs�R��PK!~w�b�~��E���[�����+b�*��
w5�I�GY��
9�E�4n����d�t��7��u�q�	#��s���
�R�"��=��'6�cb%��:B|M�"�F�"��U���_����f%��Q�����r^1�<����'���.��7%;x�	V� �����Y�TWbT�
H��Y���O[f�M������#���etq+�D���l2���o���EL~�ZK)?���N���i�`i���,����OQw��>���[�z���� ?b�Vrc�����Aa;���c��H
L�?m%2��{�������7Iq�k�\1��nb���/0��}�d�t�O{�Zu$���)��h�R]���U���1�_��	���W���=�0YgM�A%q��[�jS�#�+��Lz�,�ND+&���E��l�0"���qO��eB�z=6P���V�Q,����G��*
���9��W���<
��#�M=�Y�5�p
��I�D�=�9_����I!+���s���OdO�$�Y|z�J��S"�W��9����[�@sx���f���%�ZX�e��l���h���/+����#�._3/���`��X)+��:�k�6�j�2#���uf��O��<�q9!�D��2����tI]q�w�_��B-�f�E��$� FI�<�,� I;�������}�����t(��td�5�aWV��5X3�cT�w3.��.�j��.�zHX��[4�(���������)���5���-�0���j��[ZG�6���A��g�m��{|z���Fb���=���4�dEtR'�R�!�[�����R�������@�t�s��t�T����S��wTP����2��w�kt���1���K�
Y��QDc�R~���km�Y8�5�.PI��5��Er��,d:��ys�)%`�~t
����:Zsi,k���F{$#�U��U���l�y��H��A"K���(���$vOy����p���u��_��E��R�=P��V�f��|`�`���m��������0$�=h�H�F@��4.�i��n�_��7�Q��T6���)l-�\�%�IP�^="�4��8���]�zD4��<5�p�QrV��D�a�,�y���� >��T���;�]�5�e������I�Q��NQ�����W�#a���a��E���Ygl�"���j���������a7{Z�9*[z��8�������_B.q�2�1���Yu�XfU�d�d���� �����Ho���+���rtt�(�e��-X ��X��ye<]J��p���D4����a���e���Bi�.�k�a~��tB�@�G��z�AImI�)Y!�i�H�N�����Kq&�;��s��A��t��&��t��(���{1���b�����$�[��~�Q���nO�!}���+��i�n��+�+�%�c`0M��> ���vk��\m��be����TFc]Y�2k���T�����z9�A"�d�~*E���]I*�-���	���0��8��V�dB�zk�����*Fh�j�����7c��)����!�������N��Y���LC_<����N|$=*��0�{+\G���t�^�Y�#��	�9�c|mI
����$RA����[0j����\�
�����'��_����y[tH��N#��� E���\"'����$��2_	��=�b��T��)�:���1�{[���������D1�C�gy����2��s8+�61'��q�����_�[��<7e��pU,C��)8���(�tk���e�(����b�ACr�y��^�������Q:�$)dh���S��Tn��AqW;������,,���Q�K�"p�q;z�q"������7���k��G�]R~yI�N��!s��t)I:��7qGB=6Umb�g�54�
����P�B�8eq#)���Jh�s;A�Xpv�M`|q?9�m�Dp���b]v���0��G��x��2X�)FE�x(�W>�E�<��SC�d=,�n26]e������� X�!6c�$zm�f��!�n`c
=�u��G��8�F �XRk�l,��ZT��H+�B�3#����6Z��>� �2��69K��"-��|����GYl���@�V#�}��B����|��.JKi��^�e@jjY�	0�^��/��)e�q7,����h��`j
4.H���n��u�A��8v�?��,vx�^�6+]��bzDY4S�4)���;�w_�Dr�PB�V�����=o����0$�S�x���g�`����wP����K��-wq�qkx�|�ptW��V�����,��Rh���s��������v�d��8p����JPRpC5l��U��6���<Bzh"�-.��U=-����������F2h�FUUl�:��� Y����
=��x5��Xa��q��E)� ��/��2���TEP${��Fe�����H�lT"L��8"��0J_[�}�D�P��6�%���{
�&	��@�{Qu��W����x���.E��j���s�����O� ��8��2q������*�O�{�]�oKt�#=�8t��l�E-e�F�ICpU���z�jr����D]��gva���#,+w�4���+�	�[o��`��Q�w� }i����hh��B��� �]U� [���#%��c%��k]2��w.� ���E^Gy,{;�C
M���"�b���,���tv���[���e��Uk�M�a'�
�����H�����z���e�['����V2���5����O��e�*���NZ�<�O�""b�$�v�p[��(�m�X���R��������rhue�:���>�<4R�l�'�wy)r�\l���-tj�
JqZ{�����\J�T����Hk��}�}�2���~6��B���i^�>�-�.(�&H��������TJ�AO?�����Q��0��D����L��7�xY�2V������C��k'��������#�����!���'�����CV���F�����f w����8�����uRM�
�������~�+,���BX��[�$�3w!��qS+u�I��a�(_;t�n?C%U���*~����K�����9P����&��^�iBJ���IjY$��������#^ l�h��������){�T;�D
����bgMY���XT��9�&��P4��/*��k��:��Z7h=�n��6c[�:QK�\i=U^|
�hZ��G�C�^�r��&$�0,x�	K�
d%��O>��+��/���2��b0���}4;I������Z�&��I���T�!���m��`�j�Db�%_�����O-������%EH|�)sD��O��v�{�N��9�8	8��<�m:V�C�~0*�T��A��2*Y���u6F�����(|�����&�k�D6An����u����U���;`-�WX����J���`g�f�Z�Lj��m��mE�`�4n��������������[����K�hA;q�%b���RN�W/iQ����]�&��:~/c�H]�K"C��{L����$�$���6��	`�
��U�P|TZM�0��vy�����9O���;�w[o���U�P )6_�G��������HYMRwi$U+��:-������7�Y��M���z�,I?TD�P7��@I�G�;U
��������w�T���])K����
��|��{��[��D�I���E���V�6����fI�/�Q$�����)�Rk�����%���!�M�J`G�7��Y�U�����d6�!<6_�-::����������b>��p<GYJQ�5��L^�d���=<q���
�u��o��1���l
�&
������;��x�:�����t��@��sZ3}��������fJ%&���Z������%��z�����g�jm������<���v���nena���J>:���VgO�nC�y���I��I���FJq��(L��}�Fm��Q�J���4��:��p[�I�8}��H�p����d	uM��P�p�-B��P�Qx��h���E������N�W]q=�B�!}!9��Z��,�8�A!�[{��T����Z(�	�_Vp�F��HBqq^�s+c�s=���e��f�2N�k�Bi����;�'�L�K���N3�Rf:�:��47
��)�	s���niJ��RZ�V��W�'�k��&���y`y��<��w'��4*�Y��l6�P�qaC� D���H`���)6Y���uI�a�W���?�����F���K`C{N��Z��NiFtV�M<�B�l�7����������I�5I�R~H�-��`g**��{	���5�j-:V"���`���<�}z��ZC�U�����+~����*�$=�<=-r
��m�I�J��Y���"k�7K�I���'|��,zK�Q%�K�N(��Z������f�������Pj���l�|��k�'��0�s�j��\���`w�g)����X�G�W{z�hii�"(���a��e��J����(Y�����D��L�pp��>�Q�h�0��V�.��n�j#��+�6����q	�QI����Bl�K7f��[��~F`?��f�J"S��h����h
�pZ�c��'}�u��mh(b�kR�f���E-�B�s�DT�e�x�R�,N�-^�����rS�sF��,-��\�(=�"��Q�]�+��<"���$�X+����$��o)���B��59
�0P��D��VKm��	��e����3k$q)j���3#i�6d��)�CBq�n�}����HK���.S�zb8�g�I;7Of����	��02��~SO�������g�<�t�T�r��������x8id@��qY��q����J��s.$h$_m��;�l�iGY�����j�����sP����d-�����	�RB�OA
k(j.I���hDD��3=O�z��c���Ybi�C4�1h�5/B��k��5`�1�J���~SF����4���T��^)�VIv�]�q���usB*+{��YS����d���M
SVZ���%��e����d���Sk���*C�S1+�]���b\&��V%�G��O�WKL*F6g����ZX�n�{G.�N�����8��dRZ�R2"(:��>���zy�d�"�C�[�����l�~B6��""\>Ji
���(�!�����<�,�J@IYI�'m��aw�p��M�<��0�����vb���?��1Jhn���zq���1��B�� u�~����ai�|���}!�3��g��I�C�}g����{X���f�x�n�(��xG���4O?R�S��aw��[aH��C)�
lC�[Q����`joF]�����
���TL2$F����%�mL:�W��)7�7�������R�R����S������*H(��~G��o�������G�Z�C2KG��37&"eu�6D�^L���9����b�\�y��h��������5�gN�:��T��*H�,��������Ryc0��p
S
��x��M�bNkb�����U��l���8�������L.J��z��I�A<J��D��s>)g�8,����;�b���H
l2�{���O�y��aEh�V���P�Sa����
���������E�+s��K���Ob�@�I���m!�J����H�]5��cu�tc ���R��x�����c����D�(���	��={_�)X�[R�
�����A�P��z>�l�+Es���23T�<rQ�`�,�a�OP�25�}��x��_�y[����zh��������o?4�����cU?M�e�P�#��4`�m�e���nL;�z�2���D����{>��}��H��WS�!Y���rn�b��51f"�\H��"JI��>�e~��~=�h�Y��Xx~��s�����b>�E"p1�c�����v}^�����g���!ZQ�M;�K*���Nl���K�dF����M�?��)����z��b]����|��Xj~���/y����"3ia`���[p
��iY�M�\Fa }{[N����Q��D�������<F������$��6�g������;�~[�� }���N/-P�����z�M����o�����y��A�!6-!?��A�X��5<:�d����z����S�?>>�N0
� :����
��2����@N����~���$���Hd)�h�7��K1�B]�Y�_��Y��P�C�[����8G���G�����`Y���F��r�:���D�1,id�BMa&n}��hn�&�Ol����b��N('j�����Z��v�����o�B��=N��n+���H����|�~����%�����X�
�P�3V#�
aAm��[�4,W"
,�������wT���
���1y���ZA��\~��\��6������;��������o�o������0,^U�.*�T�\iZI����a��q��d��5�2,���M0���{L��_Px*%�^�1��|Y*�����rvp����DA�1���}�C���=�r��^�g���!7idzA-�H<)
��L`Xy:�I\-�v5�z1�;0QA7��������L=�k���r�$�&%p�I��ykh}�����4>E�Lo�W��_$L��E��>P��l�
-��Ia��8i^���M�d�Z�, ��������R��p�OmEe7! �������n��Qz��dK/���H8�'/�,��`���E[��T�����'�Y����|��PK%�?��dY���,�RGE���Q=0Y�*eM�DaE���D���3��K)��J�?������f!��b~A�}o�OH�"i��>c�`�j>Pf8�R�h/��{�\�T�_����x����������c�g��th��^��C���D3C�#= ����K�R#��-���79q������8�<�zU�]��MGa�����U>6��8����&�E2�y��H�y�����!{����b��0��V;�*�I����J�q����JAu��h|}������������{v��H-���es!�M��.y8Y��,�����@��e\DER�	J���T��8+���{t��4N}�S��.�����{a�&����>a�,�<����_j���"-ZG��JH���:H������[r@�o�E���d;?���\����:���iT�8���rz63t�� �
l�q��{t���bB�a� ���]9�1>`�Zxi�a]��l+�Z ���6���}?*��%~�W#6���D��=��Y`*���'�dR��xVMO����w���J
dBk���*o��=���a]�g��:K�Z���/�����
2����(����;o`�:��L��Y�(-��'_:B��F%BL�-������5E�I�U�_Y�����S$��������0rT{�]T�W�-���x��'��d+p!r��:��?�����!���%��������q�_���6@dt�R�k+D#��jH����S|���%Z���7�R:��c�8 �8Xm,�b����@D�D �/������:�/�D��9*�����l���iP�������mC�q�T\
���&K�H�����p���U�D/��S��\&+!�o�	��0�e�Z�u�`@� j�w��f�k������pq��*��*.�8�.�1���!�1��L����^��J@����+��������"a9><��LM����� �wn����&l o��q�����WBJ�WB��+!6�x%�]�n�AzN��5�����a%����O���?�����t�l��!�����v�oH��vO�-�pH��n�?�"��o��;�x�N[!\�a���i:��=�?%O�����-�&��Z��fHU��/`\;,	(��.��_3���@���A�����x8]�����^/Q4�R/9`|aJfw��^sd ���c	�;�]	(n��fL '"M��A�&��J��!@�R����0�N)���(�u?�d�����q���X�V�"�I��a�Jh�_(�/rH�]<\ r��6n}�:v���i�5e��� �����vY�!���<>���Q���d &�)<���@Q�%E��B�8�4�gkr��'he��g�p�w 	�������#�_\ ���/�<||{�����D�(@���
��M~���
���i��GFz�7�s?o7�8)O�����x��J�e�������0E��t��e���J�&����6�]'6M_���j�YPpc�"����`�L@��(	H�����A<����F]�����pl�8��%K��:�������h�R�v-��|�b��x��8�>���a!��D���R���?o7�v��c���y�8l�t�k-�1�x�����$���q�_�Xz�(�|��L����R� �V���Q��Y�dC\.\4�j�'"��N���z�'�)�K��I����Y�Vu'g��p�
���d��F�g��SD�Q"�`�NAh��,���BV����Ep�%T�|r�j�L
?���(tw����k���(?l��Hn�x�b)�����Vi������`����[��q`�;���3��)������o���_��V``r��s���~2�����n�bR�_
)_i�/�bR������Y�����i,���gG<�,rei��]e@u�����U��� BL��R�E��6)	F��D	��AH/��2	��6O@r7�@�J��!O6��aA�"����������4��'�<��	�asxXi����������v�d���9Y�=R�I�Azx�?����U���m������|/>�Z�.:n����&_�?-FA�B7����V
���w�X�s�,�`�F��<e�4��n��������>H� ����d*1��@CC�TeB���X�+� I�F=�N�@��'��"c�r>\�k��p^'�(
������%�yte����7������.r)�a@�9��T/��k-�Y7"�,��2�O�J���2g�I��Su�ezr.J��hG���lO�*H�,[�iIfL&�,�X�
2&��S5�'�����si_����]k�j�*<����
	'����
��!�\�	{����������Z��>v�@@8k �������]�����6��v�
2
���G@q.o�.k����JG��&�0�������p�y������CS����~9;�a���a8�������*;S�����Uc$@�-��V�$��G������g�F��w�/k$CFa���:�hx|N"��FE����1��8wv��b/���M�s�zZZ���	*ni��;�z���$��"qA�
��&i/8�U5�z,����� M�d��r��Cu�7�6�fI}Q�r� @���OoT��r��}�����!{�����s�c�g��v�������(�1�1�P�gS�M�\�~���H���O��0$G�[2�L�ue�����K������\
��u��w.���o�k��'@�$m���
2�^�!���Z�����K$�O�R"z������d�G�v��q����+��!�����N�N�
��E�w	viR�`��9��(j��C�{��+�`��|���a�*����������[<g%{_��CL���z�9�i->\��HD������j!/ ���@9�i���bQ	�������X����*��-D^�F�-�}������ -DI��Q��H���!'�!� @��|��1,BY�s��R�`�-�HH/3
"�Q-�w���b����`�n����p7)C8�s������%� �3&�>.���5�j�
���xV���	��q*�zZ�����e
{���j}a���
�5�Eu*N`h�X�-&�&�KBy��q���N��*��SD��������m&\,�@��i:Et�T���f-�G�v��.��c9d\��	6'�w��+~e����:�(8���Q���(��� 1�b��AP���8FM��w�)m��8���"��S�X�uaS
�I����e/Z���Hs�#��O�x��N���2���.yFc$��@���f`��q���@�w D����K��w�������!a��$�w��"16�����F���'v8q��h�do�c:�-z'��m��b�6�v���������V\G��N�Y
���In�juk�gE����z�N�q,D��e\\��X�z2|�i��q�b#e�+!m����|R��5�����O�1x�f�����8�6��G��2p����i�����#yK@�.���I91���
�W+��.&o��D�;�x��d�_�����W�0;0,u\,��iiz   :h��cQ�  �������Wn#��?����z��^����S�3�Cv��<&
J]�p�`�:��[K��z�}�y���-���u��~F�f8���7g��#�*���������������30TK�s"Z���37w$n�����o���B%V�����B�='.l�QW/�M<��k��\<8�5����/�m�Cj'�p��"sY�%���� ���? ������S���hY���zw�f ���x$BH=����"�>mEZZ�3��-��������?K��_sxCPT��i�����q$#���(D��w{LKq��h!WkT��)�X�����(��D$�a�{����t(�F�E
T�D���.M�J���x��&��~S��	��%&V'ANX�!tb��&zA�2W��c�U�Fv�����,p�&�8sZ�4x������oJ��!��=���H`�EH�I�p�`���|�,���T�2:ZNj����y�E��"._c��3&���K:���C0���@V�x*�t�C��7��6:�f�u�Q$A�����?1T����Y-i�%��Bq�9I0���j���,��^R�(xv*'
�n�!�-b��
e�Y$ A|w]�s���r��@!c:�C+�	����{<��\y��}97\�+<��T�3��\[<���V� ������K=3���RJw�2	Oc������)�,��\�+���2��X��	 �p��@����E.�
���z7����T�%��J5�O�b@��v�[�7+��d4���3b��E�8�^����^r3ip�L{{	�9Fq��=:�A	F,]=0�|��e�������P����%���@R���zQ�PW������<�4a�i�82�6Y\
�]�����#������g;��/��|��w��E�1<���"�c-������hj��a����;T�C-zJ:�]K���D�y��IB
������q�%�&*����w}����3�����Om|���v�(������T���.�����a�i��$�I>�������w!��t���7N��f:��
KC��s1�����E���,a���� ���A�r�����P ��L�u� ����z�P��Y�`�8���fc�P���G$������p�Bh$ L�Z-6������v]�J������GK�m�Z�Q����G����TC���q���-�;_�iVb�5e�hp�!��K����1�E1g� ��q;D2����`o�]�e|b�I#���J����,Z��lf�y�?�R�T��x����/��l#py������k�{,z�M];(�&�4�1���9x6���������2<��+�"�}�ID��e�-Sp�d�
���2gO�[,�Z	��f�t��T�Q�*�i��}q���#�����qQ������J�"�248�M������uRwp��C��b�:���X����_��H�B3|�]z@bb)(i4~���������j�5���F�|�����Vqv����%��g�j����1P�*k��io����7�����a-�t=$�^O@�)<R���v������{����S���t+����9EG
B�vh�5�}����������\�(����+FB�7���RS2�`�����=$��$�O%@ts��S�v�����0$�����)�����T���,��*?�J�f�y����V���1�]YLZ������	�{�����g#�Yu�����S�L��Y�����H=fY\��J�A�XI���p�x0���^~n�V$�����Z>�F/��T�*�����x5��|�?��gT/#	0/�r`������V� ��kL��:cK�#5�>��� ����B��<����m�I ��c�������j���M���kZ�z1a�1��	p)E�,=����25G2�%.�f���U����������)���4D�0]��/5�=w��V37% H1) �#�
�4*�uM�_W%�X$�t�U`��v��iX�+x?p/-,��F	
�h*�.@\���tt$�H�S�������P����3		����j[v�R@�|h��+����6�B���9���~,'���(n�$~��3�/�7�c�~r���=Bop4�m"PK�%����Q���Y������x�=����1��tKE)���j�~�_������C���`'�]�c��P�7�
qf�W��k
���c��ZZh�;D����������o� �.Q�MD�qr�lIo�D���JL���I����qC���4��
w������b���T+�O�	�r�&e�A}���������#��_���e�
j�H��M�T��1�!�2
��,����~ �+�A�� a��� "����x�/�
�0�\�S\��v�,
�!v0)=&z�G'�|__6����*�����&����o��_���������[��Xi�\��q��G(S�^����[�r!�����>�@~������dv)�}���	F~�d��.WM������\B�����dv���������u�w\�/����Vl+�gW�:G ���!�"4����d������8�|����n�Szw���Ou��v
y,��H�E����p�}$�F1������p����,�D��q��!s�M�F�8�u|���rh�8�hl${�8+�M����Q f��k`h�r���*E���uQ��O4 �1"
���E�H�@^B���=�
���HD�vH)���D����HDYa"x��eL9@�4����t_#����� �{8��Q��\�����[o��p���4`"��K� i���G ���i�����`�QV�p�z*�?�0���v��NbGxU9r(uFC�?��$������d�&�o'i��6�������$�GZ�Z�t8�\�>�Q��b��n*XkXn������2zwCiq���j���[�~�4�kx�f���^��-#�}�F�Bv�{��qt���$���k�&�"���J��x�Kv�8�������v�x���C�rK:�yK����!>�����aft�����[x��[���}`�0���6}�ug|���D��E�<�#��
J3�2�+�C����F��
�s��h���	(�8�:,|<��E���u%��aX��
����/-� �"����*5���F��Z:���h��\�������4�J��2O@M�'K��a�Q��������eo`��\T�!�c���d����A��a<Y�r%!{&Im��&�\{C����xihj9��"w�8 )� ��U�K'�jk
��~h�% K����f���Ue�\������)byeS�z
p��cZ�:�����)��!�O@S����L6�m�P�����7w���=���x�*Qu�Q�dIqQ \f����p=�^��v�@��F���8[+���z����L�p|gt���Rbz��<o��ME�E�E;.�jP���y�������~uq�������"~��M@]%1lI//����������1����W&|�N$�SD�qY�*���� .LM��t�S��T�p���K��4}S���'U_�@�~8�Y����k.�H'��M�4��H�G���$���H�o�:������?�a�����8V�e(��A�S+����0nj�>=�����v�'�i����/?���})�Mw��c�������W(5p�k��V"�q�x^��y�
��~�;�������ZH��t�\������=���O�=��jo�y������D�����C�|z���qH�1}��!=������x��-�~�����)���� =?����(x����
�)���(�p��V�>���E�M)^H��S���sV� ��
����L��HK��I��Xz6��K�#P����.I� ���U�tE,^{�uq��%nWF����%�_�%�s k������.��!$=���e�Y�,~5�`���!�OFm3hwgS��5��3�v�s�/x��[�=���:�Z_	2��"���t'.�M�[���b���9�����:H��~��x��R��}����?�y��!�� ='��������O���7���a��7� ��e��D���������9K���	�{U<��{O��z ]��Z
���.��I�;��jW�F	H�"�.���8��5�����Z��r�nf�2���T���I�q����8�w�_R�}=����`�������=�����2��r8�VD(���5e�����.w����z���[��/�f�9�Ug���cX10(R
^����,a�(j����h�1Q��W�E'	 ������xO=�@����]���q������{����x����)���+�x�o�q)y�-s�T��<�Ep��`�7�H���1&#�����R�6�����5�^9���9�{�������������br�KR���C��/�����y_pr/�����CEz8��yg&"=����=�Yvw{�#I57K��������C�i.]��_D����u1�v�E����5U�m���m.L@�������m��4S��y��<<`n[�H��]D�����������/1�1w?�������$���D��������O���M��~��9n��~��/?�=?>=<=d%�������k��i����b����A��s�f��_�qn�+I��n��G���]�����r�w�����a�L��r�����t��~yz �X���v��)8;QO���'=^W�����co�A��O�����lA�pd�>��������,�S�g��dX����wa<8n)��M��<�Q��2����$���z�<�o`����=b*X��fC��D��2����\-�7"�L����
q"��8)�|���g���������jF��-�~l�=�u��0�D�*�������1NA����d�BBF��"�>�����}c����)(�G"���|z1�R����b��'{Y��2��@�%k7���9�l���{��9i��7,���������M���� �eG��@�)X�n�O�����.�m���p��i��*&��L47�����B�=����7�7fSm����z�T��E|��q���)n1�0Ql�[��������V?�N�T���GT�����4�n��p)F��� ������fu�z�jqZP��.�Fy�����������0n9�����F���xDa�@�Y��b_���	_.��M�����Z�GA�To���ee�""(���7(6�<���Eai��;e�(K�I�qiHHK+-�Jno����v�P��Ri�/d;)�Z�75k����-e�(7
�Z��:�ao(��7�g3�=E�'���G��E��xf����f��������A��a����A��]����.���o ��z��.�$'N��S�N�`n���}��������L H�e�u+�<X�;�U����L{9N�{�����R�@r��E���Mi��k�,�&�F������`��.&3.�N���2���2+u?h7�U�Y���v��:��52���U��S%�>k��]���uo�+9rd����	43L��~3����%UbJ�zJ�H��� ��-���~�s3'�F�73sj�I��R��I.���;?s2G������l�����s�B��[�
��9cG���$��'�E7��?��`*%���f��9�{��+MU��[:�V*=��X�8
`��<@����=��x.z�B�-i~��8�9p���Z�f05�H�wG�1)�M^�h����9A�'%���`Y���9��D�\^�n�tMV����a N���Y������/���&Ts\!/9�������z���o�8,�8w���]O�S�vYq(�O�J�S�Z��B/��t����&U�bN��+���G�W~���,����3���;��y��`���n��s���o�u���T?����W�����a�����7��VQj]����1����q����\"��-��+�����p��2�n�D��Jf��I��8hV�/���8�f����k��Z�Z���������pf���*����e��������\�����
}V� ��eM>�M;G��bO70��z���w2�Rvc����K����F,(�����Y�@�n���/�!p��s/��ta(����^q��
L��Za�,�1����P����C��'��>#��U�r����K��K=��m���-+�|*f6�53/�$���L	:��kD����s�PM5['����������������e
��@e�����y�bz��,�m"��g!f���ZnX����WdA�9U�V�u�y�c���^N���m
^pN�����4H"�����j�����#1�M�>T��76j
�� P��|4������9��I����������v �O+'�fy����_z�u��Y��z�����0u-����\��!�[���T��\C����y��'�f�8�l:_�Bjj�����_�Y�����{3o����J�'d�6��5�W��������l���<D|e1fx���q���)|V�/�eQwj�XsZX�w��������%r4�j���#��z	T�6ku4)������Gf�E�5�Y�Z��-������UiY�u6m����K�s�g'���b�^N+e�Mz�@����7�0��#�V:�Q�M��
$��P�����~)��R| N}� ���U������zs���M7����[�~D�4�K(��b��U-�z��\�EL}!+P]��s!����r�l�Ym�q�L|��1���>��$�#��,���Nx��w���9�7���s�9Od&Y��g�i[u��W��|Y���EK� �DK���$�;�J'tJ.��uz6���L#���;!8kd���@T^�)�� z���Z�yiV�D����U�:�OrO|ema�/�r������w���;���? g|o�U)�c2�u�n<�\0�H��ik����ZFv�tX���:�����V��,�����\�}����z�:�����,�91�j���$����83����?A���m��vx�����m.3���
�K+Hs�e9����Z�^���4�p����NU>��P�����bD0��;3�����K�`V*� ��M6
��'�f^X�������9$��3��h�*D�l8w������l�+%8�������uyT�<�k��<���������������]�&SO�6�r*�:H������0 3){/ !�Q}h�-��d�x3����Qz��99������B�t�<�=��&����9M�>�3��H���87��H�����V^FhcD� ,�T���P'1��$�z�����R����ZSo���{�%��3�Re-�O�W�.��/��u��:���=����������b-y�g5/o��Pb�I�B�p������w8��+�%�:�t�bE�]�*bPz8��u9E�����	��:Y[��^�Ay/�E�'��9+}�|A�������y-�D
�dnQ���%���he.�vuD������z�������0����=M ���Iv�>���0�A��N��1��4J:�u�� ]������d������N��v)�rv���4^v�	�����J0'B��hV�G�z��q����@l�6y[�d�^��&���B�����".���]���.�
��if���"�'zA+��DC|jt������y�;��Y���,iQ?bN�sF+�D�����:�~B�8�6�o.�f�c����y-����C����C����M�����~�x9�[BpP��n��A�.��0��Rd;)��S�������1�~s��r�({;�\4'x3����������K�{i*�����H)��p�������*4-M�����!-[�P"F��
{�+2�S�D���W��%jN�l��`�np��y�'���B��R�������N7����y��}��8�oQ\�����Z���+���_�;D��l>�S�U����!-�����w�e��0gF��6G����5t
�e�w���r��]�B?���e����[�q����dr������2�O�P�
����=����X#�.�-��%�!�4[�;>#?����S�����Ie�I��0uI��Q��p�����*�����H� �.2fG�?�������,�
Rq��	nUH�D��slW�FT��,��&��8 ��OY�`�',�rW� k\i�K�����X�i��l��,R7s�g���05�zdB�eu���jeeP<��r;@mV��O�r�c�Y!�����C���yqp2<%�H�V��k�M�,�"jD����y�A'G�������|�5���m��@��M���N���i��$\�(��X[����I8klA�Y)�\�W��s�&`I�KtRa)�+�(� �	wQ@�j����Vj~M��pKIt�^8�U�'����EKWl�-I�=w����C
^��~V{�� )Exnv��������f��ft
�����#	�~���Z��e��:`
�L:�u���L�������A���Q�p{������d�d+h�J�e{�'���2%��J�]��������\���h���Ytk81(��uS-�[���
����AW��uK���(=Z��gq�������$����L�#u���
��q�Q��+J[�^��O�}Po�����[5�������c��"��
|Q[1O��a��TY,*��(��w���O�K�u�ue�a^�=�9�����7��F}%61,V�I,|��4,L2r;�K���r���j����K�t���.��z������E	�aD�Xf%g�p�QW��bQ��!N�C	e�oE.�x�N]��5�C�iD��)�G�Csb��W��PG�����9
N6���`�)��b3��7�T8���"�����w�U�@�^���v���Y��,�xL���)�6�V��~(s��B������{�����3�~��<�lu����>����[���q\��y�����B����I�	���(8������hj��o�e6�?vH;��k��[�~2��L��~zXB�����c:���E�r`"=�H���ujgh��Y<�x��9]���9�rfB�&�]����g0��s���:�~w1�R����d�G����@���%�Q6Y[K�YXm[N�����n���-f?5��:��*�djhj���+@�$	����h�$T��4��8�����g��X�N �� 3g�7�x*8z�QCE�J69��l����v��G���O�����b�\�����EPn�)J`�2*~��X�)�����
������j���ET����jK��W�
�����Bu��~�����D�c�L����4�Jjb!}�>o�2��}!n��!�|��;���.�B�ZZ��h��)o��Wk�
�g��d��c��8��x��M�WIV\�QC"�$��e&�E0bd��z�km���5�b����YJ���K���U���]�j�JftM���F���m��n]���������M��Pd�9�I�&N��.q��y�Z~��������B�	y�
��e�-wc�g8�x?��p����:�������Y�9��Z�c��N�������d������m�l��"��
M��|$4����[?1.������xQ@	@v�?/�����s���B���3��z�o����
������ yb)3c��N��E�V�����/�^�������@,��O��ZDwO���9L�Q�g����yJ[��$��w�4��4�gMz��5���D
u��q�M��`+i�Q�U�Y"�����:���xf/��6�l�%��
����Y,iK�����A��Q�P�����P�X�oC+��s-\] �a ����Al��d��i�Sf�0��������D+G�������%���!�,����RJi}��`>W��S/�r\]��p
��L�N�2��Z9)&z�����c���O���zc�������j�<���-Y['Pu�1��1'�c63�G-�@vchU��������F?�;>���a���:��0��H����s�PL2�$�(	�.9<VqjB��4T!4�`Y����cH!6.�Y���_�]��H.�����7�Z��y�-J��_
uE��BQR�{���}��{��$�h[,��w�P�o^v��� �������b[��b���!��<w�I��v1l�uo������oX��$4��l7+����T�����L1rIB�)�E�_fq\��|���S�d��pG.���T���z�^��I���Uf�F<�h�F�qv�T$���ESfu����C���p%��!��J�x
=<�d�k��aR���g�)=����i9���<5ajy7q��[�o�|��.���:X������p��+��g+��1x��9#�&����������Z��B��~�u��wa&c��-�BS���S���z���X�G�^O;��G���]xt��@����ZK�x���
J�P�G��G��E�="��� '��r3�����n�W�5f�C"�"1�
E%t5n-_Psn�����r[z�����R6��OH�Lb�'o2��&�>2��lRu�5s����H���D�>K�w�:34oN�)���z�x���vXn	��u�o���wZ(V
P�[�)�
��R�������*�1���<��}(��M��j��Q2S��<i���U�Z��3�6t�R���lW�2���[��J�&������s�c7
o�����M�W����U����Y����N	_�~����x��KYC��&K�f��5���n��Lxa��=w����1m��&k�'���\t���#r-��2��f;^`�H���H��T��>�#�r	15s�<I!�j�[��'vti�$&�Sv��Mb�1W�?��L<�d B��]��%���=�C�#����>UOg(0���,�h���e�rU�����TR����6����f�k����5Yt�1�
��<�x=b�	���W����l���	��D��/�c�H���X>I<�j��R�	 o�8���*���,�p�<��e��0�h"����:��L��B$q�QG�[oDs��q
U�2��L���
f�n7�tn�u��^��	_O�=�
��5�x�)c��D����i�w=��BK�����2,#C2JT�w��u/+�
P�jm���N�vq��.�_q^��i��$R�b�>>�����d��X�a�J/'����������d���h�A�P����"2J/��3YT�Ka{�{}P%�u�')��F�j�<y5����Mg���7>L�P��S]�U���#��>v����N�k�Y�������?i�����t���6k�u�J	-Zz@H���B�p��K��&����A����)����#[\�{YN1�#=��>������h�
jK�����BW�A�nr�}��B[@�u��Jz�.a��2�������4��G_�6K�����mq~�@�(��C�19��Q���EP0���\����o��\�������J�s��BLN������x�f�
�C���j�QA �uL�|.�Y���S'As������QfY	�QS���xZ�5
�����j4Ts����o����S���z3���k�VY�sr��T�O���K���l����M���L[���_1�I*YbJ�$�������c_V�%q�f��~�-s]�)uO�TFG)jQ=]wQM^s?�:R���I��aB�5��)0s��8�#�T/�����x�|7�<���JE:/t��i"�&�=NP�L�}N2���E*��$;&�����}���"X�b>L:��.�v*�_�zv[d���(f�;�%{��`q�N�7+T0�(!��*�f�:]�N�PQQ��7K!�����'&b���l�)��]
-�\ ]�(�u]5��o���'��@l�
�������`}E�K�u��!������PI*��Ub�p8�P�BW{�o�Pg-�������D~�b>R���W^�*�����������Q_����XL���rV5��;�d���U�^(���0EX��8�.>�T� }��5L1�/�����w]��R`{��#�*0���A����-�xjT>��Sp�WK����fA����<O��!F�i�� ��hO�@����M���)B�k�>]z��[���(y��[���rl���doS[S��{��w
7�Z��S�&q�������<&�������8��j�P+�Pf/��2�X"�p��P�y�������Q�DE�:�>wDZ��5��X"���������������N2V�U�C����!b0o��5&��cd����X��&G=���]`��������1�W�Sq]Qe��8l+��1�I	_����6�Z��3����U����n��P�[�y!�N����NE�����G��7��%1,�Y}�'�?��HeIu�����6�:|e�����+$ ���r��-
Z`[(������z���%��)}�	�^uzW:�P��uMaz���$��Is���i���cJ�32�A�\v>�E�/��
C
u��S_�H�uf�qj-�f��,^���X��Bj��m�����F�:�2� _L��]h
a$#C�r��}�TOX]�3��H�9��f�G���b�u&�
R��t�txPia���������}�������nV@���$%�tH�*��J
�m	��8o}���z�%�q����:�������+r��VP1�Ovr)uU��r?��	rJ��^�"8`��c��6`��l7�w�V�z;%�r/�
�l@���y��D�-CLEp�������S���������C��D��m�E���Cz��dn��Q��(�m��x�if�q���Y��2A�����f[�:%�;�G��,��8�IS���E�Cx�{�&���Ab���0F�+��taR
G�g�:#o����P0z/�����I��uL&B9��^c��!�e2
Qr�L;�i�A�ed*��VG7���K����K<�C2
��X�������	���r��8����)m��� K/Nu�{6H?z���v�Ag�,-`&c&+O��/E�h	�]H`!1F'������V�H*�aG����V�����5
�F�F��{��K�����T���XX�����z�&N����fZ��,9�a?O��or���3�����;OQ\�D]�����������Y83��L��
�B2�"�3j��F?�^;�Smo������1%��(��J>������|{{Ox���V��P��X��������&4D�!j#�-@���*Z�$f�`U��S\�7tN�8�\W�E���mZ[7���!0�M=�D$�e(������y*3n:g��?*���
`��;�I���T�j�U���j��
������cB�^���Noe�����-���`&K:��m`2��]�OO?�SOn0�|1V�#V	�C�}H4��
)�>�b�(����������J|��OF�����j@������������}��r������d]�m&���!�1�-&UPi�]7
QA���#�����PV�!nG�Q��m�" �<��3"��[x�d��S��N�~/e>�3�>$/���4e�9��X���+���'����5;�J;���Xa��J���L���7=��L��6������nU��.�8��?��(�[��S��h]��	Hd �v#k{ig���V�����&v'��!�,�y4�K���\?� ����msV���[P�R�K*������	�=�S��G"�U�?���.�twM|#���!}��<e��������5��)�|Y���)J��}(7En�7���Y�F��6j7X;'�DWkr��������le-�Iw��6$I�O������'B�����12��}���z]�&�I��M{��'*t��f���
;)yB�+)J$n�������$kr?���f�V�V��R�}h��Z�6�&����<�~��
P��)z�c2+���!�/"�v�vI][�8�0����zE�����s�������3T�$��i�mP�-���jI/7R�(E�A�|��=���}Q��RO�p�����C�f)K[���A�>�<�� ��O���}����fN	[�9���8���*�-��o|�(a�������a�E��1�el��RY|�~)6������"�%&�[�t��L'i��]X#V��@/�A?�N�%�T�z]���!bP����������\r���me��,��H��$p����V�:���\�W3F��)�K��:Ilz���� `&���T����QV���R��
a��t>�'/�PZ�jd�Fs(��h}�z|4'��e�:�#���Q������([��:J ���"�~���1 ��Q�
��7:��"gH�X���_U���;��Ix�h���g�fC��`s���j���WH���7d6����w��Wi�@��9���4��e>���?�h%X!�$��E�B�u5��@;8�[��������N����� ���'��l��~Q"�&����$5G� 3:�K�q`Bl:i���/���Wd
�HJW4������Q�*���l��Bq�'��@�;?T����b\=J�z+�X��������U�f!5*I��@4i��6����>�Y Be��m}8T���Xe|�@���{���`Y�MbM��s�$*�}g������Q�ra9�1���K������(��AS���TLKS��n���	e�M�4�.;�#��71�&K|����-A�	i�l��t����U��l`�8�j���NYZ*D�L�i;:�P�kU8��d�:H��r5P\7t
��2E�����W����E�b-�����H](��M2���_����Y0����6E0+c��t�I�������x�"S�8�}pE�cL �[���cT�^�fL��UC�%��!�g�L���8h��z����I�fK^���g�]�wd{��#oC��v�!A��h�B�Ar�����`���8s�N���"����r���q�ew��L�	��ZX��N&!1�����!t\��Q1
��5�\�;����-��V����~c�me�[���L}���TO��������J���@#,Ex�K2��X	"�n���o�i'MZG(:5��j���@���P��-��Y�k�{1l���I'2{C�{"K=�fM\#��s�T(�1a�H#qKz�<2�/����r����T������Rq��i�Z��u�{�4�`r�+�a�N��B"�sZiY-E\�{�c�D�C������E��A���-6>RO���=�5�#�<�|���mMZy@|�sB�p+>���e����9O���-PB3��=���D������<��
����"��8���O!�qg�|W��%��og�V���T����Z������l���n���CGz��C��s�6�r}��tE2�O'�t:����eH�u�@E�2��T���@������!�H��I�P���CP!���TC=g�Js���1m����d��`:�P�;(�\�\j������HA<-z&��h����%����(8�[\�r�q/�����}��E��RQ�|*X�������Pu���|��8��;S/�"~w�n\J!t�E=��9$�x���;E��<Q��,���M���"�jn�-S1��	*�k�&�~]�e@�l�rU�����OD(/�U�I���J���/EF�Dudt��$B�B(2���
�����)���^o��3j5��Z��.N�T�^	�hU��"xE)� g-j���@�~BT$�(�g����)�5����W�� YLD���i����dk�E �0�
�Hu#�u��8�|
���e�=��=Q�e��?*	]�(�*�'����/.��T��OG�2{��E�rA�0~�\^�P�$��@�*�.�� ��B��~�\����G���������X�'t�#�S�t ����`o��3z�T�%��:&�pB�x:Z��n@��H>���+m�A���YP������y�j&_
�����>7O�T��E���H� ��}\�@V ���P@���1J�:�(�`�Y���RH���{���a1B�C_t�-��*���2�;,� �:M�S�s���kT8x�i��4�3E�8Yn,k���%E,�U�H��	���(�*�_�������=�J���QQ|�����5� ���tu@��8z�LTR�D��S�E�����KG����T�Y�$ ��%}D(OP@C�����i�E%����W�*�7��~��eXO$"����/�
�������J(�O�i@�9�/�����A�LW�K
M������T�BB_~�����l��B�A����T���K��.d��O����+���J���������z��Od�;��e=�zTNT`$Lq"�����������z�D@�>)	�&�n�h���}�q��>�������h�3yq����&��N�o,S�u����d��$-V���Q�M��c�>���2-Q]:~�EB�lV�M^���������:��'�EMC��D[��M`V�7t�$7����S�V�z��n����/�[!Y��
����<9�%8;=�g��8�N]7K!�������kf�b��M.�A^����X��S`��o�U6U�`��;A�R�F*���L������e&��0��*[T@�4�Z U4
��Z@��Q>3��
����T�B<'����~�T����o:6{�F�����KgZv�5�b�8g3�h�b����0/;��&�?~����� �b'����)Gy�����Y�X����U�%'�%2�h!�"�A�����J��o|lC�����=�1jd,K1:�"
&s�#�����H�wSd@0o����^�{uEAo":�^��=[�t �i�����6� L�����%NW�?sY�}��^�r_���/�n�,�_h�Q���� "Q�M6�"
7)��Hj�1LM�egi��u2v<�!=��4hg���,7�l�����k!��BvQ"E)���T�6}���5��3���/��$���T��G�M*@-������h>�a8gP�J�!���V����H�f��I����	�`�����T��E�A�^���Ay�"��K�zy�d����ZQBf/�����_�6g�_�7U��FW��������"���6A��0����m������lT���q}���od����,F����c^z�p������{��Z]��C�C}<���kET�/��Y�q�S��E�����l�t�P�J1����8BW��u��l�h>ce��B�V���C�-��k�QG(����r��^p����,�`�m��)
i	��h�7~,W�L�����IW���RF�d��������Z@��\#'|=�Z3{�/�p���=���4+��84�QQ�;��8jv�������-��F]�V����(���pm-A��"x��.��	�A���7�d�8�Z-�sL��H����zhh�(N*��^���&^�����K�[�����8��/?0>�e��TR=���Z����t�B��cw+:�HQw`by
���]M�S��B��������@�����d�o~(�����u�~��"�����x����ED(�\�u�
_ 4�p��"��t����@L��s�j�0|�rT����p�l!��$��'9���]O�(��8|�|BR���G����4��i�.�0��A�������|��pN�9�!��Ty�{�c^��L���}AE������O���x����.z'%�;"@�h�;��6��EK�i�|r�mu8�@v����Q��r{���SS#aPBxN��
�"@Q�4���SE�1���@�D`��q�E]^I�Rf�^K0�<b��Z�4S����0������j������v���!��&T�-���B��,0Y��)�G�����u<7��m\�,��t��&��u7I�9-�����������e��G
H=�B���j��@��v�6X�O�wEBs1`h��"@���jUa����r<�u����/+�q�
�d#x��!��aHC�^M|�;�J��8�G��GM �L;p�� d����?E��J��et/��^^�^?tc���'��1Au�\�����+D���h�O�+�x�����#��M8:�����*�W=ey��*��i��0��*�����qkr��`O/PN5�~��@{!�iu9d��J���1p��sd�������z"�3Q�:}�a�7�����	����^�9�R�e�=��`K�+G������c0�uV�s��V����pp�	�QT�^|���@w���+sp��82��L�����e#���2��T(W%�������$.���7��4�	��b���=-[����S�V��BiK�F�>Z	�����:�O�~(�h�),-��Tv�j�#�3W�k����x2�����>���P���8h�S�y2�N;�DX���`'��@&LG�p�&�O�H������"Ct�W�� |���?`�`lE�'	V�s�H<"��F��mY����:�r��8cO����g(S
�g�K}�t���8��-�BKN��Tj�����t���m����,|2F���=�}�v*F^��l��iy0��onex���]���P*������oB�:-�D?]U������aO��,:*�z�]{���i� J5l�Ir�ItQE�h�U�(�Zk���/S���%�Y�!�:,F~�������K�P��s�E ��3=�M�YA�`���p�����`��
(��P/Z�����n�)42LT,��,K5����OE�(	S�=%��L�U�-�pN/�'T+��/Jc2�7u�;�s��j=ZD���P@�L��u�����6��1Ww�A�LF���D�V1w�w�$#A"����D^��A�J���&�i�7�u��Ic#��h�0��)[�E�t���.>��!��hN�<�pJ�e"��Z�0�109(y�C�o{1���s�����q����,�r�(��7�� ��f����\gL�h�(���-�����a�n��A�rM��7�,HN�W#h���*���s5$T�S�b���[���T��fG��,j	5'c��J?-]5���e� �
-2�"���A�
��T������0��60�<��}(A�Y��r��W�#�GG������������I�P���r��G�>��G��k�x��\@Q|]����c?��Y�q=��<pwe�4j� /��(6���M��BPu��x�+��3G�h��Jq�����H2�����b�%`\��A2�oT�'�l=����S9�V���v���mQWw���$��`N���R#c�Hv���J)l���X�6����s���?���d�$�v�F���fH�?\��9 T�n�j��6
��j�s�Sa~��F��y��{r�C�g� Y���dH8���ip���e��P�(�&V�dd�C��Vb�"�2�C�����V"���'���_M�zW+�wT�p!��\mVd�l�������k�O�?������hov8�Ha�!�j���s���E��M�u�8U��Z~}BAo)��,�L:��,K�����L����3�8w�"?%���##,\��Zl���+3,����)|BE�I:���2���G�8u��=��G�0�kr2��������MM�6&�����2 j��`����(����`���X�Y��&��zy�
-��Ue��q"d�!��0����Ve63�o��XP��JR|q*��Y����$+�q�eC���A�1���i�W �h�o��;�C��|9Pz�]^�&����'�7cIR����@/_�q���o���}���eshj��S�`�d�1�|���C��gP/����b�< ��C���c�����Yw.�C��
U��cT����])D���7M�4M^��L��H���I�3 I;P�Ha/����+�}a�p�
!���fO��>R�M��-�j�M�!(Q�x����wt*�����m����k�����Z(���������f�ca�y��-�%'iO��x=����d�g"*���(�X�l$/�����4��DV��o|��;5
�!�_�����;��`w4��� �<�hmik��xcU"F3��������{^4���Rk6;�#����1��ft	���];c{~�U?��v�������Y24p
�����A���
]U�0�PJ��Z��D@���.v�(�Ox�{��/����X7� ���V���""��C�I�>D����������{��m+��m���pO�����b���YF������IMPw``�P/�Lk��0�m������A��Yu~o���E��
�0�\��X�Cg.M���>{ZV�o^����u�����|��0g��x����@��r�����j��B�\�*���O���k
|����7���?`r��V��3�V?�{�\�?�u4������{��z���O��~���E�0>��&f����_�i_����E���z�wm���Ka}�}8���7����K�@�}���sD^��>}|�������v��������jD��	�l����x��a�|�����QL��#$Z�����O��7�\BzQ�~}6�U��d�u���n����n���U�����m���e�������G�?5uvi�/����~��`��>���/��
c0I�������)/����k���I�)� �R�*�K-�����P�fb���d���,��Pg�yX�������yy�&��a�Z�q�~��
������.��,yq�u��U%�X��Hd����3v����{���p>z����ve#_W�g����K����?E\_
5;.�'����_��{��AY�3�
�/���P��^Gny�����{[����>���x��������O�W��Bz_tm?��k����E)?���F���:��}��}|x������������Z����������������?}����������n%O����s���{��_��������?�k�]��}�z�����C������CF��I���w�O~���w�Z����<7�)��_�Q�t?�!�~4��?9������qvT�L��Z���6Sq=fu����������#������3*�%	�VB�����������v�GQ��='��D�ab\(�!���7��b�\E�P��~�i=|�F��$�(���%/{��E���������B7���<�U�B
�L��d��y�1�������2�����{��]J�v~�f�_�e5��t��wo�I����l"��$�t�[__}����r?�C�J����
��,R������|K�����[HU�:m����&>����?����y���|+�>�����%��g�������$�&���'0�Ni���}wX�����n��S���]�o��h.�K�[V�W\����x���B�-��!CM}�3�
��q��C]Nw�����-�$����p��6)�,��v���2?"2�o�������7����������}�^�X��{f�����s���s/����;5������ 4I�@n��i.1��s\�\s_5���|8�1<d�k��w�?��/E����5�U�5d��\x�������Y3����_�����~�����x��y�W5����;?�ws���k�����@���Y)R4�Eh������uLC���fpm]��/z
�1@�`��m0����Z�������&��=���Gy�;��t�^�������	0<Q=}~U�u�V�F����
9��>1#��%,����7
l��O�c��@Hp��%Y@�������W5;~>�
ev&,�����r�{���WiYA�$���/�����,�9����mjB�����!�_�����
ME����"�MY;�x��Fd��}���'���|��/zLM��_
[_��o�Rt*H����]@1�����wu\X�-f����{B0k8���|���X��x�l����)4�8��2���!���P�Qafhx�����0�� �j0+��9h���1_8���R\���h�u�����t�M\�.�3�m��E7���F�Z�w5���{��'$����R0�����&x���c���]fO��z�����p��"l�h��3�v���x��t��V��l�;|�_uHnZ��]�H2���~��vi�����(���R��P_��A.O��z��XP�o	�\z�1/����evN
���������<[����������a�	�	����cZ����~�6���+~���7K+���d���R�o�&+!v�#������;��g����vL�Y��^��#o&��c��h��+���icH��y�_�-'9��
f���zI�O6��f*�3���6N��8�~�8V�4����|n�W���j����P5>�s ^�7��5���<��`-�*>��q�'�D�������%=\���z�5�Dc@�k)��zK�,�^����o���s\�kW����q�0����`*��z���K�_2Q�q�>�yq��H��V��E3����x��M3�(�b�^9�;�C^���u)�Ek�Ca���R�|>��#L�EE�mI����A���d.��c������(^��$�x���J���A��X�l����=b[F��aHR�
�I���M�#��%�����L5��\P�jW\��a�#���5G���.�����-��]Km;''0T��PQ<%][^d7���>c��P�c6o��~W�R��v&{�.�0���h��G�����GCl��2�|9���Vz/s�p�{tN��B��		F_�z����8����W�}~�D"���4��>1��/v���@�t�X��&�'rg�n2w�E�v}�QPh��S�?��b+�� �n���vpT�,.��/�%|+D^(wb({������AVlpQx*2�R6�vjrT���I/,��z�����Ju�&��Yo��0��S�x���I�7��Y^�o�b�pF��CU����?K���%�p
�1N���"k�`2"3��,}���e��
��,C����O��S�h���,)����aNe������P�E�c�'�����%���GE���
k�����3$u�)�p8����H��T$xF��!XC|�����r�������M���B�����"��9v6�&6!�����Z._�}={������������y�����+�+���kyc6���$�O����kamP��:����?a���jit
&��P���G��������ku�)a\��o$��}���Z<������q��������\����O~�8��[z4L����.�x=�������zl���I>df���_`\�P��Y\����5AR���2��A����%���,�+�,k��1�@��1)���fUZ�j�HL�*d�"&����*��aMg�4����)fa�X��k�������y�9�����W�i�����4�]�4�F�y��@����@�u�,�@r����<9���Z��T����jC����m�B���N;�t!, ��t`�%?����$��p��7=U��!:����f<�4�8�����3��<j�����=�#"����V�������\H+)7?�Q:�k1�m=F�+�v�"YJ�;��Yk]�,�B�]��Q������a	�_���^Db>"'��x,�[+g|O*� �����Jy�{�:����	IA!�=a��ND F ~�
�����T<a�;���c�D����)G�����D���9\6��v�����
�	"��pZ�uf�a�=�2n��G;3	D��j���4��$�������LoN���������l��@L^���|�gC<����x����cQ������a �W��x�v68����$Y�����:~�r��,*O�����,?���v��Pw��2�F$�>T��p�&����<�����C"C�z�7��5SJ���\�e_?.�
mu��/N��r�!��zs�����
�Uc�%p����t����w��SQE~rV���� ���8sh�>���IFI#?;����t��B.&�U�J����P���������������|�b�:����e�I�?%tW�z�*�Q��d�r���
V���j����,���\E,���d�N��S�������u����X��"�(sj}�[u]��U����
�1�m���Pk�( ���J`VY�g�]
e����%� ��T`���:����]��]���q�<J3�uv��:��73[G�%-6���4I$���67y������}��-��:���B�����/��&I^��IB����������������#����~�"�>S�7��o�����Dv�g��	���|�X\����4{
Y���y`�hE��y�6��7��)�4����9�:����5��]H3pcT��4�F��i�����&�!��I�=�u��HSgFe���wP����|���S�y��}i���H����)���xz���S�N�T^�d���^H]��r�AA�i�)�\I	 �k��w��SvLR�1I|S���5�("��vr�'�#��Y�D$#��_i������qD��dZ+H���/n�q���
Q��E�
�������=�%�P���]8M��u���|6�s�'�f3��M��.M���U���E���ZqljW2||������1<6~b��^��5���H�0�tQ����
�w?������`�����d��R}���{���&v����xe
�n�
��S�����I�s�,����6��1�Y�OC�k��A��F����T^���	�P�H�F��'?���k��N��s�,�
94.%	�}��d0����!���0kv'�~pj\s�B�&ks�:|�|�5�qM�f-4$����<�>�E��t)EU���:4m�i9<�����W�3��juB^�E�ZgS�
����H�����cV���A^���/����]��7ZG�Jjky~{����jQ�3���-��{.�ix$88�r#r`���� �!n�������ce�I����2��P3�k��BE��b$5�U��^om�������4$n
E6&N��U�Ou%�����#�!"0�B��O�U���cc;���N;�9+�hI�D7���$��>�sT�V9�Z� �f]�K���r��j53sU�z9mq'�����m�I�Ar�
����g��b�g�������b�*bI�ICn�1� ���S>	x#�����5.=�n��1:�����f�:���������Fi�V���`R��Q�2�8�4V`���f|����VA�X ,$^]q��1��m`�W�.$"}bzT������{�DL$���)���Lk���	.�Q���<'������y�������[�������B""�b����^��4s_�n�xD�@�TeS$�!_�Y9���2��(`��}�:w
�+9�������"1L��F��R�%�g���PD%�u9/���_�	t�)������	-�}�\PJGc�-]D��T���[�����eQ	LC,����[R2��2	��b���d�v�uP��������Bcq�\�v����C�E$�i�@i@�������H
�����C��!�U���tf�-��+"��8)I��XM\�/7����}�&�N��3(�>{���tD���(��$��&��m��V���i0���|a��0)�������!�12r��]��
G@��iPC�8"����ME8�����=~�K����m_~��6��3y.iG�P3�V(��@T����T����K��V�Y��~����x����S'�
R�"���R��LxF4l�����p���yCqz��Ni��
�����Phq
�_\m���������fQ��n<��z���M����~��5��\�����T�J�1�hCU��]����d��A#���)~��Y�
������]���%����?���3��X����nJ�E����W@�����K�����f���( 1���s�6�&��b���%�#���@��b��E���JM��
B�k��T��K-8�-��u�E�Rh
s��sn�G�8=����sam���|HL�hMN�k��
*~�
�k�m������63��]�����:Mdc���b���_���k�����q[��p�AVL; �E%]�+�)��i���_��<YD�0J7�t�50_�F����#Yu��8]4/'e�
�XQ��_�[	7J�Oa�x��1���W��;�/}�!��&��"�O�3�0�DA��)����v�����:��_�Y�MA�P�����i���������M�.7��9���U�j��7������A<���E[�����OR����������/�}��m��:<�`�l@���.b}�L?n�7�����	�J�����r�rn-J�f/��u�N��a\@N�K�������:��{q���`L)$����/�~��_E%��u�� ��J�`�p�V��	��i(�:+�sD�upa���
r+�e�)�0�Z�#O]���4~�������j������Q6Y[G��U�Y���z"�$CJ;�u��;�;�Z��s�m��Ydc�'}&����N�k�����>b�UaC��m�Je&[���^���vm
���>Js�$_:�����A���h���,� ���%qq����>>	L��������=�:�ev�����jZ�-�fQ�����E4C��K\\=������_�����cZDlbX�g|�:}��k��.�k�����H(�+�t���WG��h}�}V�h�K\I��>�-]���i����?�����kk���h;:og�d7l�*��8[D%`l�����lv���]�wn�^C.����alk�,X��/c��6S�3����gf��y+?��t���� o��#	�``�yj	t��~������f(��w����9<�HCq��<�5i��\�)*�de����C���:���{���d���?���6����\No^U�
��b`�oXu����k�q��SgN���S��������}L�`�gG,�AOVR����K�k95�v�w�c�*M�l������k�Kp��D����G64�a���m���>1Ae���b�p�;4K���!��M���D =AI��w�������L���.� d>�>�������H!�Ja��V��E�:�2�z/2i����m/����0Blx��.�H���`���>��O�kE}Nh��*ee�a_��(8��P��=���|[9/��F���B'�����W%��9����V��'	��-(�Kk@Os�g8��
���,5�F:sr9r``�VG�F7��X'��?`-
�����H���d�90��g���/��Z��c|�}��	��S��t_l�rZ���n��Q��YqT�kGa�[�(u����j8�Fn�K�%�&N)`�@��t��H����P���H�vhZ�������!���Ws��`!s�A�<�����^}�l���jR��S8�8���]������,����]��q��nU�>=$�9������4����P�rQ���������V��* n���A��9)������Z�"�Aa�(��j����s(w��aL�(�v��(���Tt"����V��������m�-�gic�A:��b������fa�����En����|���7�v��;������	}�q����?��*g�!����5tBF���
\`�K�Z8���:i@��9�M��{^�����C��Y8 g�*���&k2��Tt�$;�{.U�!������"�Z��u��Hd�Z�t0���r"�<"x�g;����v�����l���}����-����
��F�4lR ��7\~,�5�i�k��Z��Dz)�����S���p������,����zz]-����Gj�i-���A���k�`^�S�y�����*S�-�y"f���z&����n]�������x�%�3�Z����)Sf���K�����w�w)�w&��O�_�xa�J]�C�?���#��W��n��A,���#+����B�$���xOq����\��\��� ��3�c�J^�4y^=��r���#�	G�5��*�S�un%b���4F��rQA)�����f`���-���N�����x���((�����Pd{8�!���A������q��ID�7�#/7�s9�E�
<(d���L�9U�i����4�",#,f��?�����?&Q�Vy������pl����TD�s�V6�%+��f��7Z��E��������l���5��%B�q��0���h��*N��c��-�u���/E�v�&�����K��?J�����|��>�')HR����
�41��Z��
7~�A��,'�k�E�7����xI	���X=S���v��U��aF��'[l���e�P���`4�����w.�eFh����`�	�}��G��g���0$����H��7M���\S��|%~�g*����f�[�S��k�)h�i_���WO��8������:���v�K�9R�&��!�4��^Q���u��I�;�D�]�U��@����������U`��[4��M;6�T����S�E����b]K���90�|.���jD��g�1i)b�d���pJ�����F��5l:�e��)�}��}���yV���ys��c'�����zI��:B�S=��D����{*]�vat�PO`mWh���/�������j�0���$M3c{��-%T���W1���_^W�t��(tY�`P���H����#����� ��2�<�,<��:��$���a�����R�[	�D���cu�����8�rNR�57@A�}N�CL]b��E����}��\��7$���R��o�d7�����l^�������v��(���v<lI?�MF��K:�����8��:LB{T��r��E�s&���G���Uj�`�g���L#�LXT�z�S���D���7<�N��m]��|s�y��k��16������������p�$G�������d���:���Z���0����h�����k��,~��#z��o"��h!'2M������1����D�6��!������P�]��  ��I������y�%:�M!�u�d9d��Jr-�#d&�3��z���	Z�<4me�V{��x��s��"�R�;.�s.�Fq������0��?�0��wy������4(�������YO��F���0��F8���j��txV����s�T��W��gAr����^[��[L��C�v���1`������y�����l-R���VM����>�<}��:������8o�����|��e�@��.�y�����&���Hz(�<������4�&�bw�����b�8�E�|j������L�~q��:��W<[���:�vc����Y�{����A�U4�������
e���A�\��j�h�?����\��l�������s�<����K�F=3���qh��+��'C�C!.�R�y')��S���O]��&jru��7��)#�}v�3r��f���0������3��P�U#��/�����_VS%V��i��A�,�b��7��8�#�t������,�����S�n�"^�Q��^�g!Ee���_`f�O��x���W������m7��I���������>]����q�}6?�������6���x��z�,��������pZ���-q:���;��Y�&c�1�"��PD���T~�[�?�M{\�D����<��Y�8���M[�� ����:2	�[_���_�$�C�K>���4}~�!��*M�b�a(BB��;Fc:��X�?h������@Z���/�Y��"�x�Y����_i�1\C�f�����%i����%�z.�yrz���*�2�6~�t�E�xw��6�U�
�,����}/���U
f���
��J����j�I�*���s�^�o+�����q��{r�3��
R���4����Y�6���L�:�k�S������i�.O��m�0��7c��Ez�^
�B��,���w���������0���N����t��RscT�B��(�������9��c������T:��x65���U�#����b:�} L�"���)@�PKF�6d7��Z���J��;c���9@-�re�I��9���xu��Q�wVb�xTM�H�>n5b����bZ����D����[d����V����[p��m>��"������))�M�i*9��������u`��n����:��x[�%>�,z8����M}VT�#�yQ�n��[#.�����9�
����/�����l\��>5(����i�������%)J�[i��@��m�5{!X-��-����v��m���Q����]�8���%��C��[2�`���*�(�
Zm�u;V��������h�J�0u_�ND&�T��I��u`j&s!�m��A�~w+���-��<����Qh������t�1����P��#I������=�	T�S�.Y\��"Z�7�q�p�����]/z������V��a���� yE_J�%�i����f��P}S������XW������$��Q�R���=\����t0,�apD~�s�+�]��@��I���O&Z���P	�d�#���D��53���4����=$K�@/tu�T��:-?$��J�i�����H��m��aC?�QEH������-hm���Z?��������H�iM�_%���1��U �e�������~}+ �Yd���"8�vy��F��+
���w�s.;�n�MB@%S��>�@"�7��R1�iG�a<&�,+:����8V��l���;�y�*�U�N�K����3^�.n�<��7
�8������I��rZ��%��_3X���j�����H��i����Vn�v�x�}iR�\���z|��[��=^m�p����<,*���@|��9T���r4#��Be*l3k$D�
l]e�����4G<g#Ob��)M*�_��fK.VD�/	5�jr�u�g`�<�1a��^�n).��<�"jB����.
��f�Ig�"]�.d�MuN�g@Q�u
w�A/�Oc1�<�P|h�1�l�Ta�}<�Q	��oY1�H��tW����c.C��������vyrZH��)��0P=S��`�G�EiDn����Q���l�VsB:�+-�������$p���6d��QPj����i�\�p{�3�B�t����������-w�����!y{��@[�����?���a�"����F��m��������H���&R���#����m��xN�P���iq��p(G�k������oI��0��*�B�����Zl��0W[!�_���*?e�� �2(��|8C=vH�/�k�!k�g}n�)�L�����X��F���2��q3P���;V�*d���2�����������U���Z�/��h�T;��7��
^m�t����X�mF���&�IR�����D�jTg�0@X����:,/
��t�����W�m���&�Y�������1���oo�#S#}�K;������nO����JW'G���J��d�����{����Y,����+1!��)��>?�\_�_m��P�o���x��)���
RV<n�����>������f��������������Sz��g����$��g������Y7�z�6����nU���x����{{0`3�:80�d�%�c���2��
�Q�n9 ��.g�S��6��8�X��A)����]17]�j3��7d����M!�L)��R$mOS�[�:��,#����o����m�no������6A�tu�����>��]?�/�y��*M;8]�@Si[����}_�}����b�F�j�2�l\�}e��m��bsAXw8�[����F��Ol;����I��E�9�.���M�n>�_}�Cz��w���������K���>��:�>����6L�S;(���ZY��pPF���w��@y��@�s]�b��-�.�v(��fGu�_pY`���M*��2�z+X`��aB:,�MD�U�c�'M��\��eY�����)���[m�r����P� =~�{��}}��cq{�
Rz�v.��������X)H��dc��N���-@'>�j��<	s��u��i�r�&��{|d��5I!H�kQx�9x��R�s
�)��k
@
�,�Z�$
D�74���u�KW�9��[�����]��j-|���<K��b�������@���Ci�����b�N�y�d���f�����u�C��;]�~�����?[�V:�������SR��7.��O��8�[�Y�� ��,�^���-��0m�h�@�=l���g*���:�� 9�`H�L�if�
ZL�xK���k�Cz�~K��8jX�����d��T��n��/��/I�Z�+����&w�j>�^5�5���!��\f��0�B������"��^��H�vy��A����y|���iuw��o��y��n��M����q#���W��i�i+�b����W�m������>���m�Td�6H����{*�c{y��m��r��O������k���;����	O�s�4�}Y����U3`����065��8��������=�8��^��c/�zU�L��o0!��I�A�<��CS��wD�|O�P	-�'�	�M"PhFa���D�3�|�
�����q�M�;b4M3����Ez���P������XaBx�W6�u�Q����T������C	V wm����W��^�������m��X�������}�#�������-��^z���{S'@��?.������k y��z�t~�����+	I�%6��~��T���z�tt����������I��[�@�������q7�3�|Ew�"c��G�#`�����8��
)�kd@X���}�g1v��;�z�B��~�}�8q^����'y�$�B?c������6L������#�,����?yI�)����=��^��=}qX�V�8C������\���O�(~)�C��
ff�?}���v�&H��M~��{:N���I���
B���w��.��'>P��qC�TVr���"�����������N��lur`A"qD?b�pe7���17s���IZ9PS�����+?3��RJ�^�{�H"�e7gM�� ��j�����Ok���	�|�vva@���9p�&�4R$�^+��������$���E��)$L����n10~$2T1���\��k����Q-�"��s$BV�����2������������RX���`D��n��_�KP�mJ��h��0?�@����/q O1k�/���������K{���vO�yw�J8��F��{,�8���i���!�ES-�$��++f�|W���6�-�m�E@��w�����r��[�f�d(bv6�s��uP�����ca�� -
jK���6�z���BS��]����Z����%�e@��u��bQ�C���C��L��!#���LmnV,8P6��v�_��`}B���v��T#�A7�x#���b�j����T�Z�����T�(���p���9�rM�]�|$��H���D����zP��R$�/��g��85���kO�X_��^����E�AE�e�=����5e��z�c������&��:����N�Xw*�u�����U���CN�q����\,?rB:��k���� ��Yi:T(�'@���e��:�d)��D��:T&���a��8p��VJw=�=��r���.����UP��K)<0Kk5EZ�u����TE=>���:$�"��}��9�g�Ml�.��E3��h����W�`x��N�3�b�8��C�k��Q`�����j���K[8[����!SQzOaj��8C�K��^�k�R�p=c������T�3_hL�{�����H4��|w��<����X���C�P�-���&�x�\���'];������k5+��:���������>���|���TQ��E����J<OH�K:Z�vT�z�����������!�MG��lsf"��i,0w>����a��o���Qcg�
i���9�b�|3�<�,��$��
|'���d}�F���3���dX�����R[b��dk4�1`��MhX����1�������}������CfZV��mo�������,��4�sx���cvl4���]�a���|H�1��B�m�����XU���K��,I�d����������$[9�3�����|M����������5�H�}Q���tm�������"�M��L�;8�����c�f��qTh	&$Hkx�q�R����D*�1Y���
j/Gu.�R���c���Vq�u����� �[H���^F$����.:��P�*��I����<����������_�x�U���!���Yp�&�(�1u��$J�2��pk��b��C�,��Z�����h�YX��EG����O�yBHv�%��A������@��*RR����9X���{���^�l/�r�����|�`��t(]���}`�]w�����A�.��&�Lc'J������Z��Sv�,�	�NcU4��U�\T��J2��k�<�b�^C����b,]�����O����a#d1�>��:Ar%�	W�X!�t��mi\�OvP}��+"����{�$#������������6��~X���YV����.����	y��h���s������*���
j~�G�R�x�v�gAM9�{+�k���Ic� ���2$�
���v�'�3Ax8�Z������<�9)5��1�yo+�p ��-RH��u�r���
����*���~���}<^�C4�La<�O�W$rH!���<�`�!���$���\����$)q�#-������D�����d�kp���D������"�]Q�s��Y�V��a���R�S����r��-	����;6�,��Qe���t��Z��D�J���-ky�j���8�1���t<�x�����_-�.T����-�$-���!&L�����c�a"iZt��/k��H�Z��V�A�?��E=d�7c�	1A=f���Sg���$�������(U��v�/x�t>'�M�.H��5�������4�3�l�7S4���E*!�/m�B"���K.L�� S��������K��@P��	����m���P������(5I�5�T�+�}�C�#���P@�J��4DM������b1���7K_����|����'%�s�](C��E`����o7B���������._y�D �[}���V�T�k=i�yT����j�<�����/��vAa������<�W�`IhP����Q���u����g��ed2xX����~H7����jt�i(���j�5�P.Ai�E��q58u����Y�W{����%�_
fl�*��F,��j����]Ot��wf��n����������&�R�����]����n
��{~0\��%�����&�1]����S�W�}QQ"t��P�*]�}~<,��8�*�T1?TI�8���O�z&)��g�����0��
$8P��:��[�P:��|q}�-^�*�K��.3������i�^�m�
T���6@>�����R/��L�\��0g^>8������kl�Y�31���j+cqa4Qxn��,�R���@���b7�eb�1wV�?��=�b%�r<�;�<�&�����6��,j���G�AB��X�`���{#)��V��9���N���TO��8�c�;]^_��4v������W���U�C�A>f���q�rO
��3:���6R�y`D+cX�q���c�T���e�`H��� ����[R�v�<�b�<�^����A9��/��n��ZG�OX��c�/\�U��z�I�@`��C��!s�l���(������MMv����T�$�Mt�0��0NHp�2�8*�*:��d��` M�R�D���< ���q����V�������;�a�8��a"�`�����E	�0���&G�(p�WXPz,}c���������Q|�V�����\�� ��2�����G��q�4�CL{��9
���zQ�4��"�ob`0���I���)b K����k�����@=��/['B/d;��	���D\������sC�B��M)��Y�1 �u�/V�
�+�A��.�U��_���������x	�	�H�Z��<u6&�!oD�!,"����>�Cq�v��R��P��
��J�� ��Eu���H�Ex����6����L�!�V�\_o���5�6���f�_�?�M�_�s�`�-�?����)���+�L��;��|	Np���^��Mu�;��#����5�Wt�`�C�-�R��_!;�C���2�<��^yhF������B�7��jCu�:��������_����')���c���:�
�
#3fD����G�����&��?�S��v�,<(��c�B�e�Hq~��O���[-��S�Z����r<��5����J��[Z�j�D���T�����X���oS��p��(�����,��I����A�!S����W����������Qs~D<�������r��������i����_��%W�J������_��}AJ��
��������?�#>h 2�����M�/����e����������@�(��;5<�!��P�� �J U��_�^��/����&E��WNx���������b �m�C�����O���Z�jt��	�.������n h��Zw��g��%5b�E��c�v�Ih��!���
V.
2
�:�<	��
J�y37^���g���c ���>��nh���T��bb#b�uQ#��m_k�v�v�@���.�x.>$E���"�U�F��Wh�@g*�zC��9[(e<��1�j�X�d$�:.�s��MZ��CPs��R�l�i�.�?i:^����!�$yR������L���HEd����A����\4i�Q��	r���N_�Af"��������x��8 ���������4�
�kfij�C���k�`.R�@�����y��n�q���1��:[8 ������yo[�-������>�[��h:�z,�/����������������������to�3t��-��~������k��Vr-x?��(�0l������e�[��m����.&������GV�~���Mfer�"��<���������;+���,���A	��s;��:^ 8.Q<�G&����c���3jU��2x8>�5����e�'�J�����Y�������"�����u�20��`�q�[��	�/ib�M���p`2]��C����-�����,�+����8�.���d�`~_���P��xE��P+����YNE��_�����6&�q��1���<|��<�g�n�����6�������A�*�B���)�sK�G��j���U�&��d����]�P�hd�J��s�~a+��4��.N�#Qq-D�cI�2"��rN0`������
SS�gf����$��-;)���D�N�*�\<���f��DE�������@�y�/O���m��������_�:�o��t.�K��8�"�0�<;�~�`]\���~�}��iv69�
 ����l,�����J�,,g)��r������w�f�69�z&HW�~G��&��f��p��r��^`���a|!*�*��t���-	GuX����H�@R8�p��)��f(��x��c�m6�MJ�����.:$�A�A�1);�'R@0�x�����R3�*��bu�h��`�XG�������D�R�	�1�_�m2���pP����+���B9X����@�Z_4yK����a�~^&�P�j7�Zl��82mV8F�w���`m�X�o?�����������x�?��(���.�S~}eN���R���}^)}H�]��?�C)��A����q�@L�C�7i����;��M����U����GGJ�k!WBz�_���5�)��H/�ZH�����?������8��?���A��JH�M���������W
�p�Y�v��~���mu[�T������Hq�'�F?��3$v)��+��t��J$�@- ���3p�>�
�F������=��(O�(���0�	��
3�������9k��XLX�����6e�G�Mr+�yVk����L��q������O lR�:F4��8\�H>�3��q���%j��NH��opt���;��[bl2Mz���L�S+�BP����s.��Kn�8v��g?&54-U%xf^_��~w��v�H�����!^�������f���9y�&�S��[�5��� vj�^��~�����.���������*�)�=����)�C�c��>�5���>��F���Hw7��"1`���"DP.@.��Py1��
��������L�	��x�5����d0���VP$	�I7o�sf}i�9/�r���=���E��)��Q)���*�W'�7���*"j��wD"�{ci$�hA'�i����h0p�3r�4��Sh�Fm��wew�)h��+����fc`�u�L��Z4I������Z���q�y�'���5�`#e��yiK�tx~��Zt�������y��l�?���-}N�����-�Q�����o��3��xp��M�rlz/�!�3$�%��?�6s8W��B�zC�����6�57S�D
���c�����'R����-���CW��+ f
?nf�g����Q���6DV�a��?��&�J�(p3������d����0��0 ��d�K��u�4����
�DI�v�������r-2��}��d���#���7w��eSd��w��vW��{���T��J?����C���s���W���?����w��������?��?����Q7	�����������T�V�����?�D��]�_
�������\����|����������~U���C��q�<}{y�[����2����g �b��g�A=�v+x�1�`����P��S��"��v��]qb�@HqDg��:�U���C?7�<,H�.uC|x`\�����<z�F�2��������g����q�q�\v��:V�/��g��4&����c���>��r��6�����	a��z�]}����vS2�����	K�x�b8b�.����7/��X65��Q���J�y�m������>v �.�_)m8���wt�+����-����
g�'o8+w������.G� L��E0�o1w��YH�WT�NI���������&�`�������t���Q8��"���0'��
��'^��w�gsv��}3�����p��U*HO"���Fx[8��4�Ky��fp�_�	N���4��`QW"
`�j����M��,�T��/{d�Mwja#�@�@��(QY�����9g�Q^�q�A�9� j@��W���p�@B�u�����S����P0 �_�+p�"������A����H,����_����}�`8�{8�s���*�s��)8i�(p]]��.��8 �~����y�Q�8 R�F�&A�H�l]	C�nj���/p�J������zA/
���������'TU��
��s-D�A��E�d*;V��~��s=�;F���ZBr~�OV���9�Y���AQ�~�7u[�`���r�>]{�r�@�u�x��@��������V�����������v�m���8oH�&���V��j�C��ng�R#k�����������>�[v���v�)��vjFY���g���m�j��[���{�H$�6Z��F�8��2zK�1����S����e����
?��������7|�`�����QqJm���s�t?�z�\h+DY�~����u�*�9_E��e'�q�&f����f*�-D������<Z�"�[���5�pQ8�z�q6,��c��\�-��DY�"S_�Z��!>���������R�$���z�����D�(����~�k�����/y�������KO
�\d���=8`����������EV��`��a>�v5�a�F���%x��)&�y�����-9�+�V�-���xaY��>c�3��3��3Qx�S����^8P�e��`�zY���;`�����k�]�m�q��i�U����A�v�j�^��v����^���N���HN�(����1���i+���B\K���mW��K��yH����)�s�����
��:���D��j�^���Q��AeF����v�-�N�+���K���H�XeF��V)x��V�f�g��d;xY����$���}=T)jL��0??�������y��� i�k�F8?�.��]�d����n�F�`e��:Ig��6S�9e�%��K�B�t�5��f��F�.�&[�j��Zp��o&��/�a�����C�������t|������CQ���8<X�)\*�3R������b=.�c'�mb-t�^����<
���E�:�v�������Y�����o�7w"T�p(���W!�$*H�@�8�a
@v7zWE
f��a�����^��{9b$�6�N��=�R���ImvK_����>9Q��4��&?���m�u��~��i?��{�*��W*�G�KG�U3H��(��O�O;l|-���o
u��e8{���$(�]�W��/n�a\���6+h8���� `��!d�J/`p�����q^��-�0��T���_+��3�'j� ����������:VpMo�:�f�����+�kn��B��<`�-�	���P�f�E���N�i@(���d�w�9[l�#�r�d���,V�`����a���n���~�e���_����0�����r�����k��e����vr]���6&W����a�qn)[���G�<'��P�W	,%��6��gF��<�B�3���J�M���ZM�&$t���&h�;�/�;�<���B��o������o*����������3/�p~�R���D����b�"�f�c�[r�6V��B�F����3��������� zc���n�E��RFb���5�bT���Jn9��d��-�+�s��w�
Z�Y�������H�7���Q^gU�1>��7�G��*t��r8\�$�[$�����/x��O�$LZZ::�j�����z�p���l�^�E�7�����yV�]�"�X������4O(���k��s�6S�J6gpk7(��TE�"�2s��
l,8�2������[�����]d�-z�)^�C���R�%�����V������?�(/���(����d��%���2���d���[Cd���;��������1�T.cJ���p}������t�<��Uu/���*)�9�xT,�-��Mv,2Y��1s�+2�������5������^��W������;5UvJ��
��s��E.��9M|LR��%7W����1�;|����`��M�L��8R!�����'y��b;4�=����:��]7rq�'Y��Z�Ld��hLc���A����v��*����������9�PQ6��
���p'�G2GF����)�	5�n�}����O���ssB��L~C�����u������P�e}K:�v':���9��:Q)���L~�h�{]-��w�YY�c�����������p`�F^)�q?�g�����/�������������f���N^�_��"��L�������� ���Zw������\cw�#A�������<��"�/��m��/�\����g�{�7m��1�}��{��.�)*XR�C�N�?�H�V����8hk���\��E���F�N.q���/i\M�={~~U
�����6��w�
AP���p�f����~W_��$�q+���~7]H�����8)���B�0pb��G������"EF�nV9=��Z�
���G��%~r���%�����*
k����9q�GC����e!�P�yH�+��{&�����b&]�"��.�]�61����-iE�V���(�Y&NY�o��G���}���q)�]�0��C�J^���*YGZ���l�^��+	�K�((��uI7�B=m����w�M���^�'Uq���P�py���>=E����E(���V��]QH'^�<���u\���T�9�z���q�15��Z�T���=��<n���L�.@�K�b��!���zj�����4u]X���3�.���F8f�9+��8c!f�������Ti8��eJT��vK�'��XsT�
��#�����${5�����OZR5t`X����V���d��64�8��;++����Wgc7K�t�}M�6�Z�fu��'�e�m"�QM�N�s$f',W������+C�9uV���Q�I]���(�xy�+��/�#Rb��":gg���T��:;���P-L���a���8��(���P�L���~�R�T5����a�7�����/,z�X��yJ�gv��[����Z��3m�yc���}���[�x�W�)��
��*%�`�sX|T���������5�^/�U`��3���oq#�G��=�&��:^��j��R���������]����b}�������?��S�p��]WE^eQsL�P���QY���AE&���H�+��U�]L��I��>����G��)] ��s�f�5�J�9��Y<�95Z��Z���u9��z�/�s��'�<C�,(��-��	
i�N���U�!�e����z
&���]�|u��L��r�Q7���C4�@ T�3�������rcv�]$%�f!��HC}�����j��x�m]���
�=�X��<y��d.�`��S��������A���S�z?fi����b��� ��
��>Y
�Hp.B�z�
���0�n�����/�G�J#���,�r#��j��>
�%�y}��>`!���_~V�e����*���x�}9���FG�@P�*b��e��4=�q�!�-DH�q�.m���$��.F
�D���B>0���NIR�1g6Ez��-���Vgj�\�z��0��������=���[ ���)��������:��:]�2\�����t�sb�r���@�~"�����2�67�q��(���x�YU�>��`�C����@�oY���L�qVdGD0n�pn�
�NP���.�6\���Z>r1�w<����js`��^������g�T�2*Z�?��'!(I�����ml�!�j�����Q*��g`���!�6���Vj���
���N��Nj�G_�>dy���)�4��?�N��I���zVW����Hr��#�N���0�dni}G["{�|�H~'V�w�~���F��x$��k#v��b
����H+ii\~�kn
����WGV�%�q7�Q�~�x
#1�'q�pG�u\����I�t* �!!W1"�h��AY-��&�Fb��c}������_��������T[] .k1f��Kb����um�d�,��)-q�m�Xh������:|3Tab�&al
q��>
�|�ef5``�s��J[�t-=Dj��Q=$B$�{���lT��$4�2d��Jee(~UIU�E�D&B����
'ZrYp0�VRx5xj����Asu�B;�!T�Tq�b<4���|��dW��@����3����DPN*	���n-�6��:e-yo��/�`�5?�O��p���y���x��X�K�D�*/�v������/��UHM��m�=���%�����,��6j�(�J�v^�B������
�c1R6u:5[=���l�u
�I(�>��uj��$M����S�$�(����'![8VqQw�m�����:^����O�a1�����|�J��{Yt���WVB��^��e1����I,(�{���a���|��i��;�P��)�l��s�Z�����Y[k�����f���"�8��,E�;��@��Y��a�F�`@?��Sk�����:�l�����b���[��a���L?g����x���.��X^n�x���R9��~�262�<�.���)������e�����k�H>�VP7n�K��a
���� �Y��:R4)^�����������/�%���^�+�q����������t(.�]��U��1F�{bf���28��N�ry�<���r��Q?��MN����(�������%W�#
� ������v����`-/��k��1*F�����9Bi��L���8o��-��Ld9L����b*����sR��I�z���w�����X�'���	9o�	�5����p��Z���h�PCg�:�~�zB�`�3�4Yme8J�����Kb\�h����
���2�o8�������/1��G�
�c����F4��.�Z��$��yP����jQ��m�6t�z�l)
�+���V\>Rd8YU�V�
F���Y{w������0���)32#�d�]fA���I��8s��+-_�c��F.YS�tt�Xe��R)�����:7�^���*�E#�pOE>��]i0O����`�)
F��i�`���n�@&;��-�&�A�$���(�$�Nt�U�'H����3T�
@��j������i�x�O�?�aM�GpP���i3�������\Z��MX��E�\�Ir*/-K�����s�����b�,>�.���Q���� ���c����)��'q������i����WQ?	XxH��[Y�{�����>jU��\�L@��Z���GV�����%�I��6�����x������0���Jf���D��nYV�;b�(DH��`��>A�>m�o�-�R4�g��"���"�r���dh�I~"��^er��\}�sm"���:��h����
d���Q6�D@���NIklW`R��
Z�e�G:.�Hxg�'#%�^NxK
CT��HB^��8�v8�"�D�(��Dm|y�K��p��|%R������N��{��K���.�����m@�r�3�9�0H�8��<��a>/�pb��2��N�DRh��
�qjZy���S��d@�*�d>3��c��t�g��G�b
,��,=���Z��l�tTl8��4��*���D�Z��8�Y��&
g�P���Sm�����g�@=�<vd)8��6���ZTX��1����TuS*�����qAq$,��Sq�����������T�a�?+BXSA#���fh��*�����{,>��.&�m����`�JE�Nn4�a��@�v�P"UDj�������{/�A$2�sk�@��qzRC-�OQq~�N(#�
Amf�i�;�����A7��0��j]S��BS�@�:�|j�c��Gde}�dT���*�a������/���J��*�������4�N�0��,���|T
W�o$C�}$Y��%I=��F��^3@�K���G��
��"�x�V���`<Q5�>{4���{%%�Q��������C��m��^O9|`|�� o�Gf�����Q�
1���}*JW6H��c�F�q�)�\�Pp%4���;�PR�H��_Tt��aQ#mT}2��X��r�
'po�e)��fbc��Z��y1��}!�k����Y��K.=o`��r(�"yx�Y�8��{������t�P�����{�)T��l�EW{�XY�$m��\��Z��T�,�G�O��V8��o��2�cI
��B�-�1�:��r)
7����Gb���3��%.n�TB��P�O��(���Ic]T0��;+^j���Dn��P��N��C'�.��`�z���������_o�(A	b2iZ\�]kR������)�bu�$#������A�a����b�����l�D@~�NV7&��>���6b���4���M��B\BFzJ�td�����#m��n?�lS�P�7m����|���
�����B����� H��lp����\6���b�p�t���8�D����J�$^Nr]�aJF�^���!�>�JI�^�&��l���+H�Q��l+s$y0{���c��]��i�IV�Z�]��(�}�2���{\���b��(�K�}i�/��xn����L�n��!����d>�1����"����52m�H��T��������Z�����%�Y��*���5����MN�c�i�G��'��9��"
c�D9u'�8����3��n�m�L@��)p@B��t����ay�-#�Q5m��q��J� �Tpg��%mqb0�5��/���0jD=R2����>���4���0��xQ��|��?f��8z�A�z��
.��A�uI��{�*h�O�j�2u��8�Q�R+����L����r�PP�[�z��j�������*d�!�h�U�2 N��
����>���|��*�[.�Q'���)tf��[0���������
��=��P���C?�O�Z��&#%^P�Z�;c��������2���v���P<QWs�&+��_��:S��f����!��\�5YA���������90��`����B�0��������P9C������]{�#���*���(@*����8(��	�k
���ff�E-�����J�[j�SgguT�e���L�(��l\�Neuwk4��D��?�i���P������}�L���w��u��nE�Dei�x�KP���Xm�U�G�W�I�Y�N��y�J���-"�B�[��PQ�*+3�#w���X��-T��y��g�����w	��U�T�-9��q��1����C��W+_����
���W��s#^�1��!������.��
=�����&��+��R�$Ln"/�o[��	S��]��=��#^�~�u:�g(��)�D���7���O"�q�b#���wk�����v��7�����	1�R~N;�k�J��V z����a����Y����U8�(>��pL��S����T�"�@/rI�*���
���d�H����6���9����lAnO:�J����1��c����\uh��f�����m���.Tl�V��t#�'B�Z�C�<^�	g��m�q
NOI��]}Lr�gI��iy�H���.�n���r5�g/�j�%�]]�����r������8����"^�Pe��c�ld�%\�.g�s-�&9n�P���u	�8�\��V�*����j�S�I$�x�SXk��F,�X��Z�6���Qm����K�wv� ��	���)����'�:����@��Rr��2QQ-�+$�<�?�����9��������������.�"�DPB(��Ez����K���a�?'L�����M|��e��q�7�e�c�z�*���2&c�%Q�(�8����rJ�>k�K�g�@TA*�C3��G����eP��Z�dsk���b�=��h�"��5���
W��h�����[l�AF��kdg���C�h��7�`2�6��_�2��T��)E,�$o���@>w���0�c�W�1�1�B��?E�WqUj��Xl������u��L�t4���9l���������,�*����_����m�U�e�e�z������ie�^}y��8���HZ�)���[:"�j�=���n� ������6I���-�`��t����W�/]Q���"�J���O��#���;�YXs-?2�O:�>���������*Q������������fRG�)����s0���7
m�V�^wCq{���bJ<!q<��x�o(�b��.&0�
���/����q�_$K>��)d�9���|k;uXj��+O������@��W�nTx8�bB�8H��+���Gf���4�TV�B�u1V���<��P�`	l�F����U����GQ������%�^N�bb�B]w"�����d��B�)c5��A�0ik���M3C"���K���lm�����)�J�
3�Y�L=�$�:�h�Z_���[c�Q,%��E�y�-��N�Ka:�gj�~��V����-���	�Tz���f������?ws�������?�d��n���(���CT$�i7C�9�����R���xf#s��T��-�pP"cL3��]�������
 y����QQ�@T�Q��Mxg)� *����B�I����}6�1S����[INm]}Rf;(�:d�[IM��/�A;�>���M�+R������1��Z|PQI�b&eOAi!#�%_����_(�s'*�{K�"�A�f�����b��!HG���&�b��X�QOs��#4�BrK�R@I��{�N�|w��B��M\�Q`0��1!�N�*�/
 cX��W���/��0�0�����tU���O���C�
r��]O6������q�?�t<��1�(��Q2��k���:8m_���i�5&��������TS~_(����OU�H�{��c��n:�=�!_.U6�����r���K�p��S/_gR��@QA\f����{7u�?��
6M=|"	�P
JhuP0����B(�R�|�#*��E����e�����P!|���Q��
\�����)�5��[`�[�m��������BEqQT���&PQ|�����K����B)�������T��
S!���
�6y���"�9���jc��7��,I\�����q���U�f�o��:��k���b����(O"��k�]x�0:*��e�9ayPrD�[~��j�or*D�!.�3:G��n�K�1���(�_�K%Ys(��e���ZS0Kyh��������T���+�P��8�,��Re�E���
�m�M�;U%��Rw���1��4��?E�g�iB�w�q�]�$����-�c����r�"L$�.}�y�;zq�~�d��*�`��Q>[�`3me���1n�_�xn�@5�u����>����`��~h����)�G���
����;	{�g��}vT����r��A�*4�V��:O~��DQI!�����K�%J}Y�z��Zvb�Fp��V�:��w�1"[rmh���|a`��Re�Z����B����5U�x��� ���|j6L1K�r��0����31l��3�lP���h���	-r��K�5���qJ�Q����1�Jm"Y(���������`����Q%9]� Y5�].�B��ET}*L�*�Q��j�_���-�+�T	"(�|a�C����Q�H^ci�m��2�9a�fm��E�������k	%,*�����������qB�0.�m��^��@�a�od������_�������424��"�6I���BQ@��H##��?�y��OU�/��)C�����U`��S'��B�,���Lvv^���8�T2U`no��^({X�U��;�3������x�uhi/G����2�9"�~�N�w�
Zb�,�\DD'���W�p��B�	H-$C��.|��cu��T�>�������PJV�@�j�\�������C��B�Hv=��q���5u�����_���C��g��,\����?���OV�>R��U�Mm�V7�������H�6�>��u�j	1L�EGr���nU�����2��t�.N��v7-��p����gNk��a��A�3��dj�q������e�(B%��PD)�x�mh��`��}n���>���������T[��#v�\1&�
F;)�$i� �'S��q���Ti��Q
 b��<��v�T��X���K������<O$�������j���!�)�r`�a����B^n����Yc�a�:��DPWv����v8g�
��J���������s��,Fb(�����p�]o���pr�+�G�����rXx�B|���#b���XD������wIk2�a�7��;AX�����g�%&*�hP�T9dl����7�������&�Jz�*�NiP�����l�7�g@�:����q���,�.�G��G�*2(�=I���Pg��wIFA��M��3�qtwz���r�C�eb�t2�.ejw�!��(�{P@�c��l�P8�0=���=��T`[��b��@�"��s�C��BE�MP�0I���#�`�H�v�a9�m��
�"�pO�
�f&Y	|'�C���CjOg(c�������+-^+����;@�i���S
�
���A'����hvR������3*R�~�gn9V���m�C�3���c|M�-0���>"�TK����\�j�<;������ ���z�T�z�
7�T�q���xGd����"0&�1�d,�X�b�Q5
�:-��cF���?�@	����U���/[e�����2PeT��VO�9*d����i��q��,�?��#���TS1�j�O��Z�����d;�+uU�w����s�C���������,t!�=s�����Y�Wc���2�������b�����*j�������f�88+��,+0����"L��
�(�#�� ��R��Z�_�H��uDX�4�D���}P����J�=4/M����G�<L��C(�v#�.<�����!����.�}6sc6�v�4��8�P��5���A&�\����R�w�������t*�u8��lt"98P��s�*
��������:��������B�hA�Y�P���N	�He0WO�l�4oyQ�^��u�1�S�[����B�Q$L*�6UA2��SPv��,��-�d�D�"4}����V$�����`V!9�!)P�a�Gz�����Jj��C��P���]m)0�-S�s��tq�(Ev�����(�
Ap�1�2�����t���uW2�$�	����IG�M�n6+��2����<�]ON�O���C��#IY�2�J=k�l+�����<��PO�R���}$�
i�����-���z�<�q��I�����IO#%?���h2���~1R�.?Z�[�V��U��z�
�����9cWH��M���qL�IoA�E�
`g�!�a��,d#_�^����L��"�vT�h9�;�;�kwx#2��"s�((W'�2�j]����������Q�\�uha	4MDpV��.s����	��Em�� R,��(�h �8�2��]����t���������
k�B�2����j���,vnl��q&S���}{�L��S}���j�u}RW*�\Aq@�/`he��Pa 2/���@([�(���C!T�{�`�j��^E�-/�X���>�$5J�[�]Y= 0���A�-$N�53�� ��[��Z%�qA,)� �;C� ���9Y^���QK8�w:�X;����������� ����XG�!~�;���s�����#o��:7�/%$��^��i���E&��!������P�7Z�K���q��I8��
n�`�����-j!��]�@9W���6���
�S(���$�����q��Uto���2N�w}�W��BR�6��"�e�q�}�"�xU�� ��K3������)�!�y)�3T�}������Y@���Yf��B\8�m�L���R~�k��~��	Mq�1��B��j�������a�bT��F��2��z#�5�Fuj&RLS
���IhB����E1���/�2k�}s���
��Q��
����1��'
0p�D ^�,�K~���q/�H�f=4V�����5�y�+qH�q��$M&�C����O71h!oz v���F��$5�L6�[����u.c������q�X�U"��`X~6�
Oa*Y�������5����eig����tT��U�~��m��RQ<
*��(�z=����|5'�v�:��0D�L1T�o/?��wF�c�PQ�eTbfr�����4�N����?g�:�z���l��-��\���f:�3�C`S(��Izo��������(:?k{'��41��X�
qa�,���7�0|G�"*�Kd/%����`/Y�8��r=*��lqU����2���g�O=��1�f�����MBKu���#C����*
t��S<W�!_�N�O�z����/�o�K��y�^���j2+D&���p{�;�zm�n]���.t����j'����W1���M�\�wg�A3�,@E�%g���K�RA�>��=���QA��t|0��I��ap*>�']l�T������s�&dYc�2�(�^�� �CV�A��i�F~��_�|YD���qL�Sa|<O:�WG�
���5��a�e�[���}�v���T 8�Gi[�%�t0��WTW����������D��U�dm�S<�����:Q�E���Q�A��"4��Z�������[=�U\��d����n�4���T�0���������},*�8>p�[u�����D��E���X�P���=:����x��T�2�Ju��f��"A�������g&���M�&(��W��+����?��va�4��8[f@����&l��kKA{Oe��BW�9l��!=c|�
���6�������#)�k@�����Z`q^��8��\������0�>2�rlU"�5=�����a��y����S��vr ���!/s3�*-�O��~�I7�i���?����1(Rw?�m���>�������|��+����?�/�o0��{�|����?���w��/���G���*nww?�eWW����������S)���>�}]���RX����.�������3�|�|{|�T#����o�����4�7O���8��?<��4cn������c�~��l��GV��N]�*���O�C�Cge]�����_��)����-~�
��P7Y����u}rj��S~������k�z�;ipD�eh-�D��>?�Z����]�/���P4�����mh���D=����y}��o���-yq�d��R���u���x}���7������������K��SR����EW.:�������~�|��^@�|���PY�u�;����8�(�������5o~��xh�z��|�7=(Y�}���Y��b�����U�����������_�&�m��m�G�.E?<�	��AB����_�����zx������	�������o����������q��������?l7���~��k��^�J������;<����������o��Z��y���]����������������~���������q�������r!��-��u���Ua�W�z������=?���dv%����Z�V~��������Z�:���������-�+%+�����h�������Q �}�����/��e��*�9P�Y-������G}(����B�h�(�HC	�_�P.8�M��h�����Fy�^��_�-b:o��rTg�r�tw��Q�9e��m��K�h(?�����/��,]uI\\�JAg����{|(m����Y&D���on
�I3��
V_����������$n��,erg�����yG,��;����������l�,g�L��	Q��e6�Z�9�NP�I�s���)n�o.��D����G
�?M1���M��<��G�O*�}������[W�C�����x�?�A_��R�z���-�Xx�z�����Go����w���y<�(�	����	oj��!�+n�"������>��GU}���3���0R�o���7=w���q|����
[b�Pt/���x��5����>X��6�������:���3��k�����`5e�%\�����I�an�#!R��`	]
!������l��z7�u����q��_�>��Q�����x�
���I�w�G��u���0���jT�0������Fl?F����)����X9��V��>[�wx��n�i'Hf�>t����� F��k�o]w�VO��-Q77d�P�`�e�e�={F=���S`��L��i����f��w�]�������(�l*��6pG�3�M1m�����
~�������|�Tz�f�7�@��q�	���Yp�����`����^�*)�ieSz'����+��n��D{�����ty�k�.�IX����z��{�N������E�z��s����A�R����8�^r�A�����E���/���k6<X����ze8K�oh�ZL��
c`:7yS~�
����Y`]���'?��=��r��\
H�(#m����xW������Gr:�`y�~8�t��I��<����0d����j�@�&���h��FO#]���h��5��B�����m�{L��.~�oV���������������$�{�<��D��,�K���\�����	}��ZtY9|��qp�F�y��u���R���
|����l��}���`���/x�n������&B�	,K��=F�*�{�[i0q�#���nR��R�*:lU���B�(�����`qr0������������:#d���M.a�����:�%$]�!�c^z� ��"	=t��@�5��U<��Y�����L�����2��L��Z�%8��I�g$
���XeX���4`���|(�o@�w&��G�����j����m���F�O*��g�a�[�us���b������)}A�3,�)����!���BuL�$��*Y�	Eo���B�BY�O<����-�4��C��O���^%�
�Z�DqDZ��gX��~rR���l�W���c������U7y#k��G��,PL�`z�u��]�^@�_8����k3���=��G_7��q���W�
^�p��Cu���������jr�	2��N-����O���?��?��1�,�
~��������m�'7��������p�nj����K������n"�����6)T�{����D��<:�NX�c����������m��qF��A�d/��S�/���f."v���o���?���R��]����h1���XD��v��h�����m��"xw2m�h�,]�����r��K������u�*a@���3�s�8�Pm��<z���G�,�y�zg����������o��������S���+����6�S��.%z��������s�N��C�\���b�r��B�}��y��u����\�*IW�u�^�V�4��X���$�

�v,)h����2�e�YY���J:�_/{?�&N>N1D�L	�~GW6S�w������J$F�V���`�<����gm�R_��{�k���U�TB����Qb�a�V�hg�[}/�&�R*'b�b?X�b8��2������$E��jc�+�P���J�'����%��������������<yg���@������_���EBm��|�R%�nD���
�
�ge�k�w�_LK{�qI����M/����T/[�~5i���7�cz�"��,���og����+E.�U�dh�y���p������@������k�S�����?�;���>?��K{���x��3���de���j�HK���m���AF������E;,>[,nC�Tgt�������Coh4��c��8��S�p��e�a��I��kDX��[-��\y���\���������^F�����s�Q����i�y�W�C�6�������>z(f�f���gl��E��K�����i{q�a�����4��
��wkIb8?bip�6,���}���t�={�������x�����
%��w��
�Bgq��,��\���-OmzY��s</�������0�}Ko�~0��.�q�h������l�<�����WW�khH/�����r=j�z�zq��\����y6�,��I��e�H���bX���P���z���)��@N
f�;q�p)�)S�>���<.\2����gqf�����t�"�-�Y��5����P��)��+��E'"x��$�j�5��D_�r�����8[������'��2:�t�&��y��4f����R�]��T^�C8F77((�Ai��P��hbs������)N�!gR��/�:,b@����\u�����e��k���
�����j4�o�d��&��/tI!����%z.a&�R�S�r�������U0�LL����d���N���w�E*f�e���4����U\|�)�����,W4�	��2��K(g������$�����A����u���i����2�+���l��8n�=���I3X��������Xn�j���
\��wdq?���oxI�����++�4�?�^�����:.�N���JSKI�^�4��@[)��j��{�� ?]����w�8]kY2WZ	�~Q�2�!�v���AH�L�����i���������G�,�8�U�E��*�Y8��I�^*���r-��2[�%�%���O�w������=�T7�����������c����<l�|:����U����[H��c��v����M||��g)�
D��5��e�y�S�?QX�!����P�PkK��������-�Z���M�!3���u�O4��v*]j/��o�o�U�jf	�s�}w��-/� o�B7fUj������:fJ�Y���u�Uf��\��a
��QXc��5�E
Bi�vT�z�����h���)��rJS��[F"���?a��k�yn/���|;�����,����4'h��kG�UP
�����C
8%���L*�$X	�������S��39�GM[[��9�>������
��j3-��~m|���g��:�q�v~Rp}}��3�0m�^���,��L����,>��� �H��3,�.�E|�wK�{f����]�E'�C�n�9g��m1}|���Kc"O>�H��@�0�L�T=���?������Cm1��`0$���J����CW�}~�aPK��M+uX�H�����1e������-�e_x����e��o	������C6q��b�jT���_����Vqu9�&rJ�?Mf"�����V�#���
�w����iGK�Sx��/Q�T��A�[~8��]U�6���s�V���~V]9���i,�UZ ��wd�`���Z�U2�<Y9���`J�����B��8X�h���j�]�%��g��Y_���]E_j��+���F\@��g��A�wo��@T��9�������V`�|��E=w.b�
#E6�)]8��&b5M�����C�/���pn�/��=:��g|�@���'Xa��^��s��g�[,y�A�*�c0�#M����@S���������a�lN���!dI�:�k:�]�&'���]><J��DB�_Xf`��l�
t�|����� �SV���[��&�E*����|,����#��9����R�7�=���LLK�;�?�t&���k���Iz�7��8��w0mC���V3��?o����^
�t��Q��F�y/��3,W���8�p9?�k��([�*�,a_�e�y��s���$����
 ���f>�C���'{�z����1W�s;50?n$(������W���������t�Y��Q�$�����=���t�Q�j	mw:����/�IJm5\hA�TZCr���������C|���'��4�hZ�9O�%~�I�NV$�&��N�>8�;��{��+/`�(u��9,��21�dc���]U[�G�?��E<pC\��:7kq!yc�� d�4���� 0���8������i.���H7��H���3���!��Vh�ym���^�B��s����T�S�(]]��z��8���<Z�u^����m��A(�'\3\�L�u�f��g�s+����3}�6?���s��S�@���A�YK��y������M��C�},	��LH��nv�=QV�
4�OY]��P�7�y+o��6%U��q��c���	
4Z��>#�W�u�������8�-4�?*]P0��2a�9K�s�R(�t<�J�b���w��m��gRm~����e�9�qqP���=4�l%g�#����O/-;���x�C�c"���X���.����cJ��f�����,dznC
z��J��2��T�h�{ ��1����.5���5�����KC��e3�U!����H�L
a���/?G��n�D�|��R�<��i��Nj����H�O��ZJ{�*��@���$��t�A���LCFr�����Y.K�hf�2�G���3xrL~�J�����2�8z!��������*�
���j$���>����E����}�:=u����Pa����J���I�\u�E��]xp��X�]��mr�������p���|~�h�Q��D��J���i�HV�h���������i��7W^Y��=s�"�c���/#L���-pX�ef���<n�6o��+g��ArT�?6E/<���&=n��$_Gm�j-�����#��������}Z���pE_�}u<��,�h�i�c�#^�oZ����h1�
��0>���X��\��������8��5�=�?�c��_-���	�i<*o"��ge0��c^�������r*� ��;C���h�9�.��\2�E�I���GU����
���`�%�����c���S4:�c��+���v�FHf��!��������������o���K6$�S�HZ�L�� �V%����\Tx�]�K�7:���t���������E��ONe�v������0+��o&��I���'�
<�*����s//�
������4m��w*��9cs���(E��R�pM@�Mj7�e���I*7b�xV�������jJ���cR�y��aT����O�2�E�`�Az��
�Zlv�b�?<U��9����!]�^�n�{���;2`+�a�"Rqq�����A�)B��f�#�Q��c����+g��l%	���#�bd��1{3�����*B�)������l�4zsd��j�eB77N;s�(Ra������w���,�"p�<��V��$�����X��r��}�j���%��F
�!������XD�R��I�K�c���k���������f4��"�t��>�z�2�a.i����+�oD�!� E2���v����m�S��f����Q�#+����IO����q�$L �� �Bc�f� �S��%�����vTwkU�4��n���^!�Z�j�3����y��c���Tb��S����������d�rB8"��7yH'�<�������tQ����P����8�����I���YY0a��L�/�Y���x/(���'.QD%��Y	R
E,��>����%
�K���'��T57��@H�W!��X=�C����D����h����w0|��������N_���C��1tB�_j
�(����abM�2��fn��st�;�����R�
c�q��j��*����Y%yq�:��\W0��s��fO��lr����CUm��`��#���I!C|�'����������%�d�%2�G�����0B���* ���a�M�`�r���2���B_#5jLn�;��xH���e�6� ����Ya���X�.��c��?f�rj���|WsgZI��i%�3�����,}�
M���n�_����b�}Q]�vk�e
��%�hI|�s=?2�[��Ud�)`��Z�����G��
�@+9��CU`y����j},�U�����Z7�9
={��))r��C��y�{��cRWg��������b_J�f�o�����Sdn��lsKCiR�x]��62�,���oonMVc~"��{�[�$�p+j���.�A��Df�������Y�h�PZ������W�z1�rq������";,��/;��8�}��Fo�X��e����dS*���4c[�Ts�mq%�~t��	�h>�G��������t�o��Sz���bl�5�xq��������tKC�"mc�������0��|������]�>���q�K|�e�Y�`��8��7��{����W5���|�#�r��(���Rya�\,������g�\2A��������Wzj����'8�x��<�?�����q��r���{"�������[6����}����lH��,��I�,tX��d�[%{���sm,�N�Z��F7zb����n���2����zW�:�[�U�2�������z�O1�!�w9�m����L�JJ �3?T�~�W]��|lk�����R�'��t�B��}�V���B/�,�r��PCY
K9����4��k�e�F���0��n��������?�r	�D��d�~y���J�������A�@8��`�H��L�YD�Y���!m��Q���*�����B��n|S,,���%!H�������fI^��t
S�r�E����00��b;}��*y����l�2,NG�:ksP����6��8\�|p���n��9�a� 9;��2{8�b���:K�S[��Z�v�:
�I.���n�W�E(�2Tc�M�U"��J�p��$��u��,��}���������s?�C="BO�=P,�"���y)j:��L��"�&���i��k�7������zR�L.7�Y����������+��#��Da��Xj]d���u����!'��Y���a�g+|I�)&A��I1�&��G�UXm�fM=���������g��b�2	���g�(/�C}�iR�v�1'���i�����f�����\8������S)���p��3��(��2_4&�XU,���W&��Fr�K�R�q{���KX�]���.����*i�a�C^���^\K}}f7�u2_&����!��)�+3��	�s��.S'I7����j,�A[e[�0������P}�8�[��<TI���=�>��f��xd����Q�Fb��]���"'���`|e	��J�s�W^��������l0x��+�K|��<$��:[��E���w9��4B�k����%WXQ)����p~���E����F��1l�����M��)������\��PUQZ_�f��HB�GY�S��1�b�SF{(�E��i�rI7�FV�A{e��:6V���{��U$N�UX��f��@k��@�����6F�T�~������������(VG������~�F�m���W�P��MV��)�#�|K�|N1��N��Ej�\�}]���V�A@�
�m=t���l�2����&�%�`HU�-sAJ��V�e?/�9�0x
^#SF��������HT����!
��q��P W��E�pI�!���0^IJ:�{��#���P#��]����#i&�R*���.G����]�D�^�kkxD�H�"��q�@������P���\���a	|\�0�9��>�H�-�������z9Td��)�PB�iz ��&Y�W��e
�-P�������H���0g�R�HN��x�N�!H�V�TLu��pi#�C��~h�32��
�Ud�2��:�x��m�������[���=�4�v]\%KL����c�s��~X{�t-��L��T���
~1e����QZ�"�
���e+D�)�
���)�+�]n������b�L
v1ZF��	z#s�6{���N\�����`�,"(
����fR�QL���Y���"�i�ek��.hQx����S���Z������\���&�(Q�D���������Q�A��I�{��hS�����6�R?�4{!n����G�$1�7~��i��u����e�`�"�����>�7CGq�v�A��&w}���+��El6�vh���������<M{�����b��6o,��Ta�,��M&�)Z'*6������ZJ7���G
��q��YF�����Y�<���*�����d�	f8���8cZ�|u������N]$�Q_�Z0'�:=����gwa��Z������c��V�C��C��	�'p�	����� ���k
���m��i���E���
�!Yc-)a�L�6��90c�����Ba������M����&=~������K"�;c�$����(��3����
��r;��<��������&����|OP� R�l��l>~�B������2���~�������+W���������(.�m�	
a���Pm�����S1xJ�������9S]�&3S1�b�L��4��m/�^����L�v-l[����u�:�*��y�u�g�J�����6�����H��qN�0u',4q��1
V�����$�V��9Z��^}�.���T������	�|UdGu����*����+i��s�X���:
���+dk.����fHc�\:����	S7Rw;1�7���n��6ukIm��]l/{���.�.QB|\�
���DX�PE��u�^��}�x����o���a�2��X,z6f�8d�-����U����\N}���d�3��J@3�l�8���h��8d��*X�<`:�'j��,e�\\�!������`�p�bOQ	���Y0��������>�hdSHA�GB�q7?�@	L��m�i!����g�!3�}��m��U)J�1��LF�7=����x%��=����I9�t���Z��(	�	Wym���`��&\^'���j���N�����0$�@:���	*�C
A�X��>�H+�3������Noa�^���Ef�;��H��]����|�nHE�H�
��5�1�N���!^�����1�����vH���?#�9�������Yx��D�X�*���Ar�����cB�>d�J�
e��(��N\����������H���`��i^�����������h���5�&BD�������^n�;�n&Cy&���i�����i{�������*�������'� ������3p�����������r����a�%��qF��u��o�����wr�m��{���LO��q�h�\��8���Y�w�|�N��vu����J@��^��/��L��O'_A#�o��K)��y�7a\@:����1���2�������S��8�'�����0b���
��7p��8�����#x��aOrj���j�<�DA��Y��D������el���A����W�%��|�t��rRl���t���.f�D/���pO��
�LR�s'3�h�{�����r?^�d�;$���B���as������}�T�i�k�/�QY�&��@���6[|fuP��]!�U%�������,�k2pKv��&�d�I��$7	z����f�������Lq��9����B�du]����Yo���|��>��#��81�3�����O?E���mts�M'��T����E~a�H:��*0�������[�}����`G(�(��_��J�}gR��?�����9�@�Tw\��I�r���I����
D�� �!]�/�����VDoP3B��h�Z!H�N�c�3�YH�PUs.���T�c5:p} ��Y�����29'��Y��)��h����p���������}t�
��P�L[��{p��h	�I�fK=��v<�b
sYP@D�>.C`B.>�6��XsO�!����V��>�1�����v�.�
������v
c�S3�p���Ya�\R�e4;$g,rd��
�{+��Cd�L�3�Xt�X?��a�0������$CQ���N�_��������'�fR�uOZN����:.T4/�8��X�*��0�
t.���uC����^�4�z��:�]�n!��?f���:���0D�9�a%�����B�"V�8���"2�T`KV��4�SGWn�O/B��;
��V�D���1����]��B���"Z��Yfa
U3+Z��T�0V�d�]P�$�
�"	�z&fw#a��!��5����}%�Qr��3B���q�s����yw����}#(��H����C��8��#NLIa�2St���Gf`������k�p���~�(.��>�)��%�:��RS����c�%��_�}���a��/��zGK~
U$��X7�sK+�����;s�d�
c�s����[�����>M;�0��D�"�o�Q�)F[��ryb������B)��\�����a���=�n�1<��a�rLC
�;�|�4�9:������~�wu���H��7�M6�@Y�PU�yH��-���3T���~���e%�����sio�S<�WqJp��yZ�a)-��u3���O]��H5�p���T)p�4�9��EC"�;��q�B��2���X4f?��%K�n�k|�Gz�Gh�1&h&�S=�z�m�T���WK�t�~���A
:����BTv�%@A�h\�@V�����@b�������=V_'�Q]�]S�iW��M[��.�C��\}g
������e�����������;�3t���9����L�]]v,���Wh�������;R�GT�`P0��-��Ph���8H�^�'�Gb��2f�~�KTe�c�	�VN'g��X6T�f��us��|�-	x�������f�xl~]�^��1���(���1;�����g��B��0�
���K�n���4F�����O��U2�fCu�.�� �#l�AU��u��o����t^��E4Se���R�5:���P�n3`���RW�H\f�\dw�����J@IH�����Q�!���������Nm:P����C�����S}x!�R2�p����'XI���Am��&�6/��S�=��#��������cz��_���9tC������K_��e�J+r�\���8����Mv���b�yx��It[����
��H��C��6���B��f����F8&Xh
&���n�KgF�\����~��><����OY�����@����*?�q�{�����sG��f
�8����XGq��l�+��/k���S�������&�?������������x��<���?������t����>?=�����
��=$���%�
�>}�F���Y�G������(^��h����t}���a��r"����P`�` �-��I~;��^NY�����$1:�5����8V3G�}���5:�$HO�gq�q���8����5^�����S������3v�����T6��	����HWUP4T
��)b���������s���5�vY���@�J���~}����9Wh�#�Ig��g^������=y��>����{����oO�����1��RO��\*�ErP��JT*@��`��Q�O���u�]Z���SV���@��4`#������P)�tN&�c��l����� s�R��o|X����g��K�����=>�g���JE��Z�U`�x�~���M��n�����O**�
�MB�����~�&��C3�T����Y���
T��v�����y�lo�S�������%Ml/��>m�����x1���Rgyg���@��`nW�q�M�9��9��A!�j���<��I�At&�m�G���%Pp$EYuB��FZ.I��D������ht xQ0G�o��C[	���5���_Y���Pf������c���F�����t��1*�by��&Hh#���k��l������Jz�?<l�zN_^vk����(���:=b�������.}^�a���]�:wh@�&m�$���c���k��:�ls�|�K�F�����=�e���8`��.��8����3�D�j��]�
�����L7T�*�1�j�1��i@�T�fm4xp����B���O.����#'>��$�c|
O�n��;]u�<��R��|�4:�%0%_�"d�,�����\�Vy�]�~6=�7���m���?������Xr2�_~��������y��O����O�*N
E��������h��n�B��
�V���9�������J��Bs��>oj�T�<4.�j-W��,�h�{���8�s2��!*��(tN���������NG�b1i��l�	�;G���F�Y}�!��f��g�^���@�y��}�6c1�����>��Z�������ns�5B]	����
u�i�TIeH3@=�>�9����'m
����
�atT
��E*A$}!� ���.�����d��� 	����,%����~"r��O����hz�l�k������L��?�vk�����*@����3z�x8������C
�n��@�������t6�!:�WXG
h�{	m�D�,[��W@j%�����,���yF��R�(�=�����a��}���u�v�u�����<���
Gh@/�*��������P���vx��W����u������.�*���t��?��}�tyX�����|u���V7�G�����.�a����%r:���GG���&���?�7�'�P���S�"�F�9�hT��s���������B�6/-��~��*�uWe@����S�L�v���|BM�3b���y����R����ve-��I]�:���'�}�gL�~���0g��''�@!�U��Y.��g��jPB����#���K���RG�
���y��/�x���r�k����c�l� _�j�p� e���dZ�6d���C[EU9�B6h4uY�U�f��uYv�#�i�A�vX�AA�Q�������EO�e�
kx�t��
�
�,��;�����Xf�-P:�FA������[��H���PS�}b��#�����_�s�`?Y����p��H��C
�I�����H��E`���Vj�14]B7W�_B��>�����b��<�����%�c�fF�W~�������\|����a�������uq!�v�,}U3����u��y�H�{���i�����a�bO��@��� ����*w���^VyF���*?����u�����f���V�����`��E	�|�p��H�z���5��v����0KG��K�T�ggl�X3�^T��������@�gz�(��
�A�f���Hj�{���^�@4f����a�I(XU�Gi���e���#Tq���PPQ���D���<�%_�Cc�q}H���e���x����<����sh���8�#��M	h3�e���/'(^d1.�T���2�����/�`8�h�?@4����i�7z)�b+�zG���}���x��v>#J�pn��	1�-�����y��9�Ys'�����1u���b�4k,�����^����P�#�{��}���n����P �v�Q	�'����&_��f��A|�-:
D{������8U���	2o�0.���T�<Vj�gt �X�'�j�#����@����9k������,D�����e�� _6���Q�kBCR7R�fP�����H�?����P��z �X�M�bd���������1�;5�%�pS���=l���j��6,�%�
w3�/:��@1�o�*y��E��8]���"�_~��Fe��!p}H��!}���6������
�{T��<o��n
���ff# z�3���q��Wz�<mWyF���n
�,��?�nQo]}�Z��I�n)��q@��\	���%1N�a��/������T�}2k�s��z��;{�!5���%m��O�0�#�����]*#�cQ��8����*����x��<��C�Q��]~�;4�1����-����<���Y��AI!��Nx��(F��\M��RA9�59�}A��=�?�O
�TD3���!�Z�E������O����n[s�V>�).�A�����,��v���*��k�*
�lN����<��(��k�~*����d:�v�8�eO��`4���l&���~j��L�����P��%��m�]Q%�!Y	�q-���Z@���=n���k��l�3!�TZ^��,1�W+u�1��A@�����~U�W������x��cR��g���.Q����b�jeA@Hf��������=��>m�b�"OF���Uut7������>�h� D�o��5j��h;��HI���d
G|��*�j�����U�FE;�����!���Q��)nS�u��-E�����	��U>���u3q|,I=��Nv�����W���0��:�y~nQ�.���P����S�:x����_���������c0�8�L�2��B������*�>���������0����2�C���pe ���i;o��1����`�u3/�PA*�o�>�(�+��A ���i�����cP���X�)������(�k�,x����0����6S�v�+���e���1v���B��q9���r
�8nZ� ����oA��3��Z��u����zC�;R8?���C�}�*Me�h�]�� \�Eo��`{T�I(���m�[� ��&����#1���pP���r��<��< ����x;�O����R��.t�'�������3�/N�P���?��j+R��4�k"Tbu��$M�����`t��P8(l�C�:�����A�5t�m� H�����)d��`�E��qe_�a�@nD��j�|�,�
�y-!2V]E���"���	:��z!}�f�#@���Ct.Q�B
�9����y�1�f\��P|���������Sl������3�F���
<Z�����K���"�oX�u��0qW'yn�z��
��?�0���<�'_n����<����a9P{����#���X�w3A�#Bu���It��>FI^D�0/��0|�{�-3������>���of��|mi0����%`��[R�����P*���.�������������N���))G���������d����7B�*c�0�������&�>A�nE�3�S\�?�M�wn��Bm���G�A����h�f^�g�i����=�#��`�_@A�L��=��O�U���R�j4�F�������r#"����w�of���`*��2�$/�����s��;+�I�[�~����-������`(Bu�@�����u5�l�n:���:T��sS�,�Z����Db�Q|Rr�t�Wn��e ]M/lFJ�Yk2X�L�$�8�w#��e���4�7!��rMa�5p`�)6
i��6�i��?�d(P��~npo���/�zf�;�����%�u���!�Q��YK�����=�>���URp�F��M����r��|�0s������+�
��L"������Q�{�MI�W'�]`������H��Y�8�g�.�����@���0����R{��AxXC���
�A�%������Myf���I��({M�ah�*5�,D�����?������B���-��V���-|g2w������`�RVSLC+^�������t f�`C4��.n���,�����|�2��#�����I!�{�n�bH|we:�]Y8�p�
�L���7u%��2�=�!G��oDa,,��j�@c��l����%g���@tb�&�Q�+b?�ZM�IF��=�W8
������3Qt�r���C����=��E�(^�{���I~�"^��OzlY@?�[9I+��jv
�N*��FGri�5�R��P���i�B����~
1:�����	QI�ak��u4^���{lQ�Y�~}\�G��yB��,G�$�����[zEt���(3���V���p�2�S�,��Z�\�@�fN�����~����$N%�w�����G���M��#������ES�U�^d���/]Ms�������g�;�9q�Q�8�>ty'z��.�Z��8�f��;!Z��!��Q'?3Hb�9;�X�L2}����)A:�EsJ����U��}����7&��Z!��L%�e`8H���P2���������v�/�k�>1��	1;p|XP�����X'�}?i�K��
'�A>-�trF_
����R�O�\}�"Dw���M���\�+�����E=}H��l�E8T�Upe����
D����<�n�B!��8H-�A���,K
��6����P,����#���`�X�k;�C�C[R�L,����N�8� ����&V�3���
��a-R�`���_�t�/�/[I��.�R��<�X�������V@��6@��6O����V��^QT*g���2O@�Q��zmq �P�1�����Y�P�O)��o�'2�/��A��
9X00<�YPE��)z����LnC�Y�8H#�����`/s�Nng���|}^s&��C�a��A\�t�\+��"3:N��f���.&1j�������{P�R�F1�Gy:���"8:oS�'��.��MlI��s��W��� �!�L�C9�?<�����Lg���j^�H�V���W1���9n�L� �B�>f��
�<}0����2hT�N����V���4�t��H����F�,(C��5�k��-kG��"�����A nh���U���ns]��^�:{���s��k!]|����{K�SKz���^�}@��#�h4[K������L3��f�B8�a�e?I��F^����,Ht{D�.��%'2p{"�*S�C]
�seWR���dm&���v�;�bL[:�B����.�44s��)�2YUL�{��j2��l�n��[#�jK*��l�E6H" 2������6����U�K`���Q3;��%r���������'U�t<���C,97��:	K�,p�a�_�H�.<��e\�������@�v7�[O7�:�V1@�[/�	t*��d����Y���%����l���p���^�8����!A��=0���2����u�O���"+��*������C��}��:��G��
�)�\���oF>��dd��cl��#�Qi�8�k��/��C��l�a��������L�\~0���9��>������x�a��h��O������D��_w/"4���^�����zh��$�P�
N�2���M���P��
����m/Q~�w��VC3�*��������+��q���.�8�v��\��]����G~��hB�.D��S_@q���W��6������&�������-D=+y�E(.���������{�l��
���@+7�=�O
M�@c��\"��������_=?�g�/? -��[����
�K5Y���A#X�Y��'�����I�,��������v6q�8�H\w�1�i�F�����P|�i<�s+L�4�@~
N�H�X<�X0k6:g��1���biB1�zc��A���r�t(���4e�gt Z��cIa1����M�+6�+s9!��F
����(U��`s��:j�W��bY�Ky(N�j:����kAa��j�^������}��K(�g��}r�A�>������'
C�@���@�}�,����WA��49�S�����b&���IGd'���)43�� (�aNT�:��,_)���S0G5�*o���p�J���b��[�~�1������P�L�Q�xan��KJ��	�WCME�� �$y�c	!��*��o�r������&@�Y`��=���7?�3��������4���o�8�^WuQF����=���^�$���^���V��	oH��j��������88������'���	*�[����a��A�W�P���9D�<��W����Z�L�2�T��NT��zbR�F�u����#L�����'����+>T
��r���a��{��7j�C�@E�Q���J�>�W��?X�_���/__���������^:�mb��rJJq��{�<L�Nq��`���@nq:�C���U��������p���P�=�����xku��C�~��C�����1���)��2v��''�������-Z�R��t�^�ru����M���G	�w8`�������C�W�8���=���9��0s/������]2���	AQ��Z�k7u��H���!�@���B���"D	��8jW�h� ��Al-�6�6bPB�����8���C���e1��o�k�DB�;5��A�I��@p�CiN�a��(�����&IU�A�������op:�i�}^0���` ��	Y+)��SG�!�.JG���x`�;Z�.�Q��~��7��I�7�
m�~N���-�����~��`��&�a_�����t�����	qu����{5�`y1�����<������y#���F@Y`�$�6*���F/���.�����o���s���n�{��|~P~����	�cy��^�����������Z{���BO\J����SwK��O<]��.r���h����TY�T���J���#��X���5��/�~���O���w�!m2P�����X��S2uI�������������8��mZ��bP@!��}Q�@j��M��Aa�0����G�s|9��**�FB
���Y+W��-�dH��������W��'�L���z����pk��I+�F@��V@�.��G�'2�~��}�t��F?�n,cQ��c�5�h��f������'5�6* ���p+�
�p�<�Q����}�������`?����X5s���X���Cq���:��bjy}����v&_�GM�%�&�H��,��jK��/:8�
D�-d�a��Ka���> ���T�A�E�l��m�������y��K�n�.&��>�s��������=-��??=>~�v�E�� eO�__�*����@��>��"���a�����@O��������<�n�n�����k��^�����E�P�q�*�����}�mT��~������n��]�?/q�v�Z<n�����%r��@��&_��1��Df����b#��q�o�6y����[�	�sq
Wi@/_�n�D����>>>��~�q���;�Y<���XN*���R�$����H�]:��+�c�5�S��y�Y#X>��,Ns����4k�#y�E���#�Ku3^�����hqW�
)���;������]�/
��e���C�,HpK����4
����$@$#�G����T��:���v��c��N�f%�\}<����y������
�E�����;2�GF\�s
a(Y"����C�q�V���84��8�}7>����`��D.|���djG��^�!B~���~SwQ{��J��u?�hw[�+*b {��
tw����e����������D�@����)N*���L��2O�v���#�z�/�m���u.�����Z}�������U�.n<�����O�-M�&#I.�~F�����$I��aPS��>~���q�oZ�$����JA�/����{��
�R�Iu"��6Msk�tw��[�tl�,+���>�u,X*�K���f�����/(zz�f?A�@w��kV��Qm��<��%�� �@��
)���6@���&�(H�����h�EE@/�O�O�_M��iu���q���������>�f����oWY��>����j����a�����Y��Q��@c���Q�#:�k��AEYa��p���|������00�iZsr:i��;|
a�u^��������7�P��z�$��nZ��y8h������r���
�c�	?�X�U��5��W*.���x�+�S?�����M[�G��o�>��p������������"v�j���������V����O��������zD�<����[�����>������R���������:�R�_��nN����?�����%�^�|��w6���;\���J���sJ����T�{�;�3=���c<X����Yu���8n��'�@'��YW}�����'f�������y�r�����`��GZ������c�K�IV�}Q�6�zW��J�wW��O�yi�D��f�]��3����'����M`{�h��,����X`E]����z��N�`�P���]�E�����M|x�-aro��f%L`m���y����G�j���.g����9���Q����~|�Z��3��3]WXuss�.9�W
����$��~����9h~:+���r�6���,*����xRA��&:o�7�����^����;�z!�����S{�����@��q~����N[��������+*�c�2�:?�"&������&��3]��D���O����1��.��}	��l�W����@H����f�����X-�����C��]@���@�v�SL����v�LZ�R!x_�rl7%�ZK3����I���pS�����A3{���eh������Y|��o�O�
`9�����\��1�"���q>��X\_�xq���i�nm�P5��Lk���bGw��Az|:me8��I�K�P�����yE��P�[�#���vD��Q���=����}j��~p�����0���4Qn���jp'	v���+����'��I��\�)
���	i�����u��z�8�-Z���d������������KL��n�u�JcR������f<s%��l���x���:���}�5da�2�"j;�������z8����'�*m:&mYA�j������0#�6�������{zl�[��2���l�q�+q8���[MBcZ��>�OM[_u�u�UD��� ���H��z$9�I�Z�M-���w?'���<oy�)���n��?z�5�mz
`J%�fa�����!U�+~s��	��
�A�L�������K�����$�������hZ.�C/s"M~��:�o��Wb��l���2�m��|�h�+��q��]:��gh������&K����=�q����r��!;�)�}=��w�� "�P�|�WA�4W�6���4W&gkA>�d:[��6:u�C�0,U~G�@��������*M
��"KPq�q���s�(ie����KN�y35�KR�%����{9�57�j�-[������8[ P�%�|1_4�N����ku���V�������k-/�Fg�9sn��%Q��q�t	�m��	�����c�J��I��r��W�+�jI�����sO����*1����m�0�+�c�{�����ff2����l������O���t�W7b��`3�>��>��r�mN}�`���\��M��n�t�j��7����v�I�����a�H�>.tG��������zk�{�����������@u�K�I�Q���.�O��/p7����<�m�Sb����v�)_t��,���JY�B�u�3��V����X1�0Q��oe����g�:�i-��_K��
f�+���/�Z�K����mi���4�7�q�sR����=��o��=4�"�er������e��y��u3�b��C>��ms22;�U�VY
zX������T��G���s?t��l�&u'o�27��R:�RQ�Hzu���P]�1�e�}����
�4��������,�,�$[ES����I_�e�dV����������;I#���>?�B�f��6Z���]V>
��3����ik_Q�F7�w1���f3R�:o"z��z1AU!UQV'�X��F1CB�����:Y�E'���uK�L@����)d�P�o������j2o��\�)�17!�u�pr.��-`>���C����kyR�O�f��m�.+�I�����g�vD
���}������|����!|�X3�	#��w���+�\�qCeb�!��FS�)�w�]�3�uo�����`���U'�[�M���2LBw���M��B��#�}J��V��"g�2s?��9O3D�P��k�]>"xv���1|K�;x��,0���s������xt���mH4��tl�*�}y��2mrH3A�T��j)��� �6�:���'�8H�����7��������8D"��MQ�s��	���jF�W;c�OSK���+���jWH�J�s.�J��W������%XG'n����^ndeK�\*	j��#_�?3�Z�E��$G��W�5��o�v�����_�)�f�i5����*�[���mY7�{�|�����oA�����f*n,�>U��kC]]RV�����.��8�������,��:u�^V��s����]�x������8b��b���|B�y6mA.m���Jz��,���c�g��jga�)���>���� a�(����	dn�S�C����H�X{�i^���^�/��W�6:���-�p�a�3��\��������a������`x\�mz(a���N�*�E1��y�`����\���������S��Zu�T}�MJn����qh/��;���������*����� O+L��5�DwH=5��8�����������Q������l�D7V��~�'v:�(X�������(z�����}��w��!*�����0��V����F���7E5]����u,�?��0�����8�
�	�HZ�JX���B~�;��6O�D�Nz�w��E�H{x���>Y���xj�:@��4[�'�*L`�\���D��e�.�!?�/���h���y�V�!���?'��,q�Dg��]�3���8
���]�{�I�p)T�
�����QS��:M�hA'�
�U?�3��CF�3����Y����������Zj�W�b:aG�������������8H����0��Oz`�7J[��uZ�������:&�j�������aET*0����8��$uu���m��y�$���Oj��P�B�2����U0���&������=@ �
�X�z�k�W���<37����X�bA�g��KC��6Ua�.5W�������������a��E~iP�����W�����C����vY��.�JH=T�N�$���UW�0�vXf���&�����t~+�e�s��c���L�b?@��[U����O�6�
��y*o��`:b-M-O4�*]�a41�eq�p*��S��w�O����;oC���vT�bh���7�������S�V*��oPb��i�+����G��5��IXq
6s�*����~O��p��O�^�v�����55Dj\p�h��D&������WE[K��(�_\�[��)�ts�"#w��F0��l�k��$�N=���i],��R���
�.SK}Y~*�)����4�:]���"����O��&!�)I���"�e��x�M�7uWv�$r*J�n\nYj5�Y�4���`���:��n���!�uG<������e�1.���^�Xj��-�;���]gy]R�m�^?4[GOP�yG�����.Z b�d��������������<�d��)��c�� v��Bq�6�Ma%~���_n����){F��m�n�&��$�zk8Z�Tv�c�W7&��(e
���;'�(����t	�h:(0Br��3i�j9���i�,��]+#��RdXv���,=�
�}���\�d�?���V�}�z��(�j%�X.���F��&�Hq
�S����\ eG���c�9~1�;ud���������g9�L��4q'��������k����l'yO��W��I�B-�bqV9�Dt���������N�rd��l�V���[���Mpy4�L��'5�k���K\�iu)���E���pF^�L���o�x����$%x|�L�M��
	������T���x�4�p��#���j�07�m)����y>�z���?u:<N��q:�N=?���W-�����	Y-��������:m�?K������y���T?k�FH�G��/�=����H!0R������EH9�Z6S!�U��E��}}7���E����L��0��,f�g�����k����������I��������������k1����g��7�����S�p�RJ�����pa���J�N���'���������9�m?f��
�����M&]��m��]�5�9{;�2������~���c��g0������l�`]P�Q~�b�D��O�#����� coL�y������aW���
o�K��%�Q�@`T���0|@"`W��C�@���$��������Pw�
��S�1���7�U�o$��e#l4(
��|X$C� �J���T�����!%"`�
��b,<�#��"����
\�����mJ���P^�rW�:qC�2Q��WU�)XVQ�K��r&��q�j�Gp�j2�[��)�85y�8T�3�p��Y�G^�b�h^�5u�O��.�� ����C8��~�B�G����@^���y��q&g�;/�T1$�_���z�]Pvb+����VENh��K���&d���=e��#mX�E�
�����
�w'I�#��ZH���n�QR�s,�N������S�82�7�n�Q_��Bu����7�V����}��7g(���_��I�N��Z�O^'tR��[��t/���Q��y7r�r���e?�cS��?L��3/��^�����3��R�]����z�}97F�u�^�'oi
e�S.$���Y�q�p�7e����Y��(
�Ys�rKJ"[��9������d5���Tj#���D�c�����e�t�w��X�i�$'�R5/���w�xd����)T��A����^�f����s5W�����*l�G�C���[�������O�ph��z�����s�
��7W���sc(0�Qf�����;�CQ����s��>��5Q����P�G��	��?���r;4��.��n�w����e��6���������x�3�`�K5�r��F2.G�������p7��!4�����il�f��
�{�:A4�Vt��E���v�y��{wd��Py�����ydH��3���H��l��2'?���������Jd
H!
�"
��Q���"ax���
��Arr�q�����7�r�d�r��|!mS4����R4M���Zw�>�y97AD��y�MUZ
�c��e�H�yo��$�+�.����KEk=&�TM�4�-l�4E�8�D8�*�t�t��JN|�J�����-�8�YD(�sz��]�Y���vL�'Z�:�
�(7j����V��Z����D����|�{HVNz�p]�)���!�)�f2669yN�xx�����Z�u�/�Ft����������`����\{?+���a� i����oz����d��
�Zx��-��
�����~�S$�g�h�U�M����'��`�����B�E���C�zB_u
5��m���WgW�]�������!b�"�3��<u8"������V�""��G�,bi�������w���E��.���{9�"��^�I�}j�,3����5M����D�\.�����cm���Sm�n8���)��l�"�4n=8F�v�#��r5Z���`���.�v��K��u5a�@w�gh���jyWM�F"A��"�[=���9��c���1�$DYt���&K�
����6��O��3��S�i�����tC�)��|�h8[i*�G����9�4v�O2S��`�u)e���(��*���d������Q��]9�S���	���E8������lK�
�2�������P�z����-4����^���8�Q��#�T�
�H��V](u�����K��[v��5��'�,l 2v����7�,�+�xck;c��`����i��>'�w��.��6
��k�l����r����V�������Aj��u���4��{V��M��n���}ede��!g�$��6���>v1���X�^�c?�<������������K�j�Gpw�5{\9j�!����[�-�X�n��Jt]���>�>`�O+��dh��� H-�Hy�,C�a�����~#����a���y�����M���
9��M_9A9]� 6M�ngjckBm_����dM�NfuW����9�wW��`(��^^dU��I(�I�6�e�;K�NF�Y�Sg�}
�<B]|J�*��FJ�h�/[�����R������1����Ax���@[�ea;FR�R��:`�����)�ZD�eW�B}6b��
>�����%��!��B�l�i%B�Uw������NJ��,�������H*�H�P�%Xs7Y���)�^���&�LP{V��Ql�m�����Zq�
YPf=��DT�8B�(%��C�]c�P(L	��bM�r�����rV9�S ;J�,���h�����4P}��T��rF�	�	c��k�����@�$�A��tI�{
q�����s�U0�Db���4Kb��:(�GS��6���lb�|��yQM����8�����@�'g��H������c1T\�[r��Tf�(<
i��^ufB����R���%1�\���OY*3	��8p��|��"0�H�v]n��IB�?�f�z10���
�O�S�Z�!����!S;v���	M���z�����\cs	���<i�DH:��`��aQH6�_Nd�P��#f+���F�rpeA�LpBzo���Df98n-c���M���g�L"?�����u
�7��"��9����%|�a�1M�J�oA{$����$���J���IT����f�H��K��,rT��=U�������C�b����[T�\z{*�p��Y^����Cw?#��6��fe�
������V����V���A�96�o�T�>;T���0d}�����W��b���M���;���e��>�|r]�k��0`Nf.�������w{�un4�S���[('�.��"�����Jo���0��^�"� ���Pq4�(�$�JNY<y��rV�a\��7��v�Q�q
4�.�>]Wy�z���6wK}[N�R�5��Dj����5���n*��uA�EAH��,�����Ek��)��o���f8��Y�,�8'U�W5�"t��S���Jhv���Nj��}y����L<NL��J���=fj�A��W�WO'���Pm�����k���8W�e����N,���:���l�����S7nTe���"��j�(��?���*�W�+�����EW��9|�,�����_�����0�s�����N!=2@Pz��},��W�]��9:"Y~lr������'�.Ph������E������{/B&�N�{����I��n�#������@}CW&�3A����v��C�u����#B���bL
|m1�{!3��P1�*-T�R���������=�3O����S'U���1y���n�GK&�<��
�i1����H*\����,�5M��\���H��
��������Xd�����-����dc�d�'����v}�9{�f��Z�j�����X#�~o	Q3�i��Z��zVB�m�R�h��wPr���;�����b��;;|}��$��
\�i�N-�
4��<�h���	�O����Ue�n��KOg2S�qLV�[
-����Fi\�I�^ _�R�ut��'+��41q����I$P[������L� 5>�,�H��05Y�`���=1�E��<���`�<��+-�Y�}u�DA�%���N�S��r����n�A:��U���:1%��	�
�rO��.�&��������!��g5k�`LS��@���r��^����xU�]]����Fx��'9�('�R����3G���f���: �]������P�ty��A��H8j������2�?YE�[qg��j���H_c�j�B��c���+9�L�AN��.+�A0T�%�N�P�d����.���p�S���6�A��`O�������tO��u��4d@��M�,��V�xO(�0�uT��}��;D��jn�~�Zh!� �~�u�f����v�j�$s�Sq����{���:���4����l�R���Bd���;���f{$gq?4�^v�������Y;�����M�:�~�mD����!qR���L&�
r�D�����R�F����	b�L�����C4g��B�$k<t-�����I*�q�R�nVn<��@@2AB�E^�����EU�M/�z�=U��B�����;�\o���*�2�D0V�,](��
y��q�q4�%���[�2d�	���d>���1�i����~����@Xj�a��h����7���dq���$�pI^
����D����N�J����AZ"I�;g��H	}"�s)L�����0+Y
r��K������[T~R�Z�g���}�X�g�-R���62�"K�����~�&�������u,��R�O=���N�#���;�t�R��B��hF|M�W[.�����'�"���(�7�����zDT���cg��m>� ��'e
 '<���RQ��m�c�Z��T/}8�����j�T�����C�����C)��IB��{��j2~���K���>�0���@
,2�C�6 ��?�^����P���M|��}
��h,as#W��8���t�(����N_u�W�����J�"��&�����i�EM�h������`��S���.dg�}��~!K�is�� s` �/��r���.�����.�`���\�����
����rx��/�d�����i��Mq��A�i�5�n�l2L�zg�������.�Z;���O��C������KK&��|tk����S�G)���"d@.�_����(��q3)[g�j���G��\J�u{�,GV�`Az�u-]v����C��#�`k���t�]J�X��Y�T�'�N�Xy����M��s��>>S���+�"a��M��.�?	�s�Q�W.:��Z���Y$A%�o���C��������"mE �R�H4D0�&�_EX��R� �$�W;'��?���� 5���]�/3g��0���sxn�XBT9�����f��z���t���]UU�`��2����\k��!�
b�h���n��t�B��.Y�PG4�_��/�Ra��ih~�D�����&OEomD�Vp��0�����Q'��}��p�7�-�L-;9����a�����[<��IA�V���z��A��"����Z!���OV$JU��|��w�0y�y�2x:[�Zw�M9��7��>o.U��6���{��\ybG-_0c.��n/��Kfkf�c��8��L���M�lvB������%6B�k�=Q'^�[�}>�]�B:�0Wg�h����Vh&-R}�O�����5x�@��H��#�����9|���]��}��z=�=L��c�����P�b�#��PWx�`��������M~�1d������j���E����1�j���
��-(c�;p&� ��z�v9�b����P@;�P����"��T�Ax��	���7����jc�.w���+�r���S+�2�:�ct2�Pb�O `���0���R���T�����Ml��BA����!��z>�� ���}��p�L��M`�m�+��;q�>�q�^(��$g�\��CGq�VS!��Q*���G���P���.�K(��d��P.��r��-�N�k>�/�v��8I���d��$��f����k8�� @&�t�Q�6v��{n���W���L		B����+Ox�^],"������
��S6w?��������:�_����=�N���Qq?�
��$}�5.DK�!v��R�������{9���FI�@�%��^b:C��&��P:�����ca�Q����!v��'g����f���\zW�w�Ra�qh�2;l��8�v}�X�����,��62
��@��HR1�U%�����8��wO��cW�b+dv*s���:^���������r����������y�!B(�*{��:����������n��:����H(_�
kY�{��1���
�t����������>]��t�r�3���jR4{���Lv�[~D��M���>}���������4�F}1�K��N?QkZ4�B\x�S])t2T�V�)2�{W&"���t��O�Yc���<�kj?g�d�qO��=|�c�R3�Cyv:j�+c]!C��C�K�B����JA�K�:�e�����Ze��j���
��1�1=����Z�q�_�g
�C��6����h���U�$����|CU���������U���xz��v3y�hb+5�������4u<�p�`����&:�=����"�E[b�j�\NvV�h4=c�7jy���HM��!=���g���$�����y}�� �CR �+"b��@{=07=
D�T��hp�g���
*�`'�v�6�j���	�eUu�����gs�=U=��������\��w�/�:x�,)+�����I���	|�.I������ �.Qg���*Z��������������l���0���H� ���x��/�s�'u	������8:��O�����-Kl�,q0E������Nj���"�D/zW��W���:6C����K�q0�����!fn�����B��Z�MXP�=�"��P�v���\����`��j��0��`�.Rb�'�ky�l8������%B2����t:�M�.��R�6,�HkF:P�S���(���**!d��@�sbd����vw'��"����	��c�wH2��O?�>b�����*�T�
�����<:T���9��nM�,�RQb�������$��T
����'l�������A��a����k_t��ln�]������Bx��"�X9d?w��
���Q1�j�t�s1b}�!��OPaH�t�� A���V��B�3}T�&���_)R4����5�^���J��Zo�8n2������ ��Q�He���bS��S���Y��	Q�DtUI�C!���B���mX��������o�1�p�{;P�P�2�R���B����$}SF��X��G��M�=2��D�-�GO�a������j?[$M���X�;���"Q��������S�5{��kc2t��F�"3��w��UqU�mv@�th/�T������V��y�E��C����S���v������aB����r+@��F�c���1"����U!�����hb�@D�7H��>�I6@�tu8(�c����o*4�x�Iu�C��"W")L���d!ep���fen$�y���n�Lp-�1�u��O����:u<6�Y�
�����l�Z|�6(������<�k[7���g@8e�u�Z�8m�;����d���wrQwyXo24���I<+��pB�9t)��u/�����=O8	/{�E9x.'���A�%��0z���^r���2���v)=���:=<�����S�8V�l���7{�b*�P�&{���������}:X��x(0���=���}}a�����{���e!'0F;|Y��n�*��.I��^��KgO��-'��	D�_f
���_��I��_���"�8M8c,E�e�P�]^���k�Y����a���5;��^�������
!M!j>��H�d
jz�f0N�nx���,GM:V�>�z%�7�Z��z����x�F9� ��%�"�:>����Q�j����F��i����.K�8[�,��}�����m*�|%�
9Uw�F�j5A�:�0����
�{b����h�O-��� �m������:���?U��Q��9IQ���!�@�%&,@E:�h����	��P$/�L�M�����ic��!�������*��Db�
��U��"���M6��&���2�$uh������56"��<)�Nur#B>��w���A���o]a,�+���P^��h���/�������9���P�����i��@�{m��JC�I�4B^x! �sHh������>;C!��x��Y��=�NWd��h-g�!��>B���Q����Z��/��Wh��du��>"��I
uw1}1�����_��K������T��7���-��A��
�i������$-�&�� Y[A�S!�@���D�oE?J��!�zJxG@O��Y�v �a�|0�����i�#�Q�����$�L/14��[�w���u5�ja��C��<���>px<���������
�1i�0:�,5C3H�\M'�+H�9]"T��� p8��Z���'�r��HLS���trZ*E�5$����sX�Cdn�@%A�|_�u��Vl�qr���'���U�r;��a6PY�=D,-8���/'h��E*U������Eq��}a;��8�v��2��mh������i�J��ZV����3�B8z�s��$ak��--�[
��pn/��w{6��4T�+	�P"X�ay*����������&{M�ah�*5�	<�N��B`��0t���p+�g�H������}X���2��B���
W(e����W�������"Z��`�	����a�G��xb�xu��v,�y����g�+��w������fF�Z���2���L�8��[K	�x�||�Xa����2``i�'�b��9!�r�w����C��Y{�Q���+��ziq%�Q!G��.G�P�k4�	*�W��b+
R���J�����,j3�������(p$��o� p�ZP��'TT>�������*��<��FGr�}�(}[t��-��=�����9�k��wh�q�����&��n���	5����eto?�����p�����c&G�U=*y�o2�p�
u��[����s-��Y|���;�y<���O���a�������kUOl!�B���4�����{�\��Qp%4c2�������)R��F���t���r��_[�S��7�:4����Asf�`F>����B�u:��7�$��kI]�m����'��h�ja^Q�@z_�:tCX(*���m�H'����W��ZrdH8��I�&�r�	��/R2��M�:z;�9BC����n.�i�L���>d0jv���&��&4�^��?��tX?�����n�B��b$y� �P;��Z��v�@y(f
��B��G� P���+G��������B��w'��W�J�����!��*�������t�L%���0@�*
	A�V.��-��W	��h��b�9.�Q�T�@`�2��a���jL�F�t85�W:���a����t���{/}�_��t�>���tN88J	���B��6s��BEi��e�y���|�����z�((�T_��E"�.��,CC��������zR��l�[2�L���l�-85p7f.����e@�<B�d:��7^3�'�Z�^�Y��m2�C�Gt������A���8�!Zt-�n:fvY����
�"+��o\[�2��(���m�4!>��N�K! �h���U�8�ns]��\����}!�sg�k![b����zES�Kz���^�}�����X4s:�5�}����K3��f�"0L?c�M?��$�Z����j�Yts`tF��Y!�-�`0L���:`.'`��R�4P���|��f'���E�\X?0Q�5�M�f��?E!Vf���
��p~���~������B������2L���2�u�G��k'�'���8�"���*]���y�/`� ��6�����>�"'���HZ�����)Ie��`
����it&s�%�!��(����w���Q�L�����:���nQ)�)K�32��!�<�4�/���9
�@�����1 �����am�e�`�u]ui@�tAO
�>��%	���p�v#h9�p�����N��Qg�Bh�"W0�8����h8Y�5��	G��)�J
�gmM�����|(M���#f�Rr�1�DR��n�2���)�py2HaVf
������8����E���\�����&����"�o^s
�+��6}l�������$�tt;��1�n���[$���Z:�
KFuwSP!�NT�����!�������A���=�Q��C�"X�YS��C��I>�ua*���Ey��n�a��P�4%t�ZT
��v�aZ�Kd$�FtS�*�����A���a��N�G�����/wI�\s�8N�6*�W����B2a��-lM�3�Czws
�:�%���I�>�ap*H��hoX�}�eP��jt��6u0��Wu��A5)ZP"�
�q�K�si� �QAN�F�N�,*��,_&�#���M0Qv��h�<��,���B�:M�(6�������� ���Ti�
��L�������gr���^�jO����sJ�V'~�`]T4�����]�^����
�U&o���PF��^�-�t(� �hZ�x�����V�0n�'*����:��}O17\}�\�
{��^�g���4B����z�K�5|������P!��B��R�����\t�EER���t "a 
�c�+J�"M��yod�N��,������9K����(**�����S!l,d[�3/(�E����Q1�)�������e1�%o�kq��;5i�N�����(N#����q��������_����2�-���[��`;�7�~"�|OL;�H�1��>���}��vi`���I2�u��U�^�������C�d�_�l!
o������z�C
��L*T�EF�6-��wr�R'����t1N���4#�4?�k^��N�����������Yw�Qa�F��_�!�,.��Z����kw2�x��ELf����/���^��� �y�����=�n����[gQ>�����1�dY�p��%C���������!2~n�p�:��I�"�����W?"RVw��B�����A�w����PeP����*�;WID�H7Q���R�����<K;�JC��?�����zid�ln�rXo�Q�����`}��l)����:D�fB�88�GE��P����?^oaUS�r�a���ECP�!C}@�Z_8�Y��e��AO��w����d���+'��`��5SR�"�xe��""��]�����&=x��EG�18��^��P�B���0k���.uO���7G?�.����"H"kf�Z��p��,�=\�st��
d��v�?�s���A�@F��BN���TJd���\*�"�s�t�����qh:5Q�20Z����K�������mB���}U������?�	�rJC)���$�+��z�A��p��5�4)����+���O��@QXuP���V��O�\�b�g�g�V�������&������?���"S�����pNE(G$^���T���j�ZSsPk%+��t�P��k=�����?
ut��Z�����"�#[1J�����/K���o�7Ih�7|�9(�7�j�������*�9���e~�Q����+��������o~E1������i�����{um�2����^����������k}���������_�������z:�������u�\��~��}���u�[���}���pc�Ka}���9�7�X����z2�|����#���q�������c�����<|y~Q��f���O~�`c����o8^������0����0��[��dxs�������<-��a���+���~h�?5���������$9!@������B�d�����[�o�6>����n���8��z�W��9>�g�J��?Y_u�t.n���������m
������S���[������W�>f<��44�V�~��'}���-�������5�{������)���YT�xu��$�x����H�����:~b��������"��u�{��0�������?�,��f���\�[��X���#��������}�������/n�%�V���hb����7c�F�S�+�ux�]��7?7C����G�_����?��J������`����1n�����}~|����������^���w����7w�O��������������rs��x�� ��%O�U����?V���������K�����7�"�R�U���9��j����v�a��fR����w�������y�v��9�]v��hG��k;����-������r�\�0��#����>7�y�j����VI�m�s���������.I ��@W���/_����NZ�M�(��X�Z��h�CY~�} tt��^��h*�?%�G�;��P����>%K���g�B�r�X|�L,f����=���������_b����w�s��M����o��#���?<-���T���=rP�
��_y0s�rN�p/����^{x�<b�&��Q(9����-H=�e#��`������^]������eu��R���;�g��(�$���i��c�
�S�mKw���:#�%5��� �m_T�
���E*����z��]7���������/C�P�h��]Z&� @v:?*\}�;��r��[���zGMu����B�U��r����!I��������s��yh=x����e-x��k����X ��qA�|����xs����,U[\pY����Wn����� ��A�b���HQ��
����Y�bi@e�?�����3/x|3�B����MP_@�2������{�:�Y8(��%naW<�'����K�����V-���C�V*W����"��z�@�7�y�b���e�Xx/���b3������W������P?�3�����������9����B^�����k��d��}���a�k�-�@W����p^8����K��w�b��1ufYr��z�#�����_��Bm�{��������|��<�%i��UQ�q5)�?Wk�� ����w98��#��������zj�h�x��g=�eO��7�A\��,|��;��Mr-,C���\����>Y�)��e�j��j_R���{Y�����z���c����?'s�������L�s��~������X�����,��������%=��z���X��)�������g�g�IfJ?���{):4�5�%��<W?��Xg�%g����h�Xj�^�U���;�O�_m+����M�I��Ils���5m����g�^�t<����B�}2o��c�������[�G�x���)��o-���������I[�C1`\�$��#���$[���{Q^t���\Y�sF+��=6����Z4Cys�'�wO����������';��L@6;�~��Sk��W�����������m���0�t�V��z}�Mv�m{�f�N`��?]�>�~�/7
;����o�����V��C�bz�Vx���*��������T�Q��\?u�S�U����E�����bu^b!x���8���x�<x����t����n��w^�w�-������\��,����(`�|y�����W^]��1y�D��A�V�p��~���F�DI��'w�K��-�z���m��0_�Z�na,�Hq���D*��&3�*�2���>����������Wo�(�=����g���d��o�W� ��:H�Q��\�3k�M�,�:~������)�y6C��4�����5����~yRk{y�/jZ~����/�9(�����������eq��,��#���8�52|��J�,qc3�'�E	&��)��-��0�U���B����N���6�=!jUn������`�GZ�������M�!������m7,�p(K�66��N9,��>)�^e�
����G��^��'��K:��V�e��u��{�)�������z�,�]��Xb^d	��[��, _��5��J�u��C�p�`���4�W��Tl_Eny�c�<�����'��I|:%�X8���~OZ��?��D�~��I8��[�C=F*<XNt������/�sU^8���47�[oz<��y���4S�'Ydu~}e��Bt{�����6�������+=`������N'�m��-�?�$�5�y�m3x��?2p��U�h�t��s	2^����0�������������;��xrUh�h��+,�l����p����n=2����K���P�1��ddG���hN+��iq�^MXG?��K
�
Y�-9����<����;����".�����1�:sm��+sC��\�+g������.M����d-��}?����fgJ3%*6�5���$�$���e��+A ��'�h���<1������8F�����������zR��>���&�5��������n4�-_�8P�5�2R1����+t��c��d����>���\��&N�U��0x�Z��A�/����6{��O5��a�>AZR����t��W����
2u)����}��6f_�A���"�?�u�,�%	"��I&�$�W]q��a2�M�h}�4.���T���|�����2��]|.l����
����%����5�7�6�����]]K�������-����A?m
c���>����E�G���M��h���O��sm����B��>Ujk���|
������}�P{�\W@�����]�_;��<��[����M=�Bo����`�'�~X`kX�O�l��p��R1t����0��y�!x`�Z�ZL�"�J?�g�V�r]���$K��^5��`DU.��dOy�������^o��f�^07	1a4{ue����`	�_j���c�lN���g��A��K1#�z9��.��zI�����G������wC�;���Mc�O������J�?��I>�:����2�W���)�O����s�~�oP��lP���tbq5��������vUk�7gU�����}1J�B~�Y���x�
D�+���T_�u��fc��`,�x���%������{���.�R�o"���C��> �����g,f�a�QOF���6��c������%��%OdK�{?	�V
��������0�L��&t��U���\p�����]C[�l?��X��p��$��>��n[��>m���7/;�Dxu:f{��<�*���t�-�Xu�����_�3�7���6�$�\h�V3{�V��Z�a�ygux�)zA'q���pF0Uxt�<��0�*��hZg�w���:���g�A_j����RR��E�*�� �%{��lW����F�d
`���	(�'��r������'�kiG�=O��������D�.����������\�UQA8]��e��Mr.�����A�]��jT�[��K�P�Z��cn^�d,(��>Q���q�����*���.���������m��(�^�t�iq����	Lb�������BL��@�f!
�f��4�I�A�����E�B6�� �<qV��)>���$x�b�D��4fK��Ri�F|\M���H:�u%N���a���p��^���%U8ms���h2~DL��Vg0Jy���M����\�s�����_�����{����0�{��h%��dD�!/Hs\��4<����������EdO�p��5,\:Z��pI
�V����4�J_e�vY���ny\�6C��
�����+�"u%��|?��lID�V�M���l�_n)"uYL�~�������=��
�WY(��JJ����_�X@���s����k�J/g�*�:$��1�c����cU
�����.���$��<��-f����������-y�
��\M��PQ�q��<���=��
?w%���+ek����z��z���c�F<Y������Y�(9hue&����c\�S����:k��g�JuYSW�|�>#flYIwQ�Y���w/�7�l
F��G�sQ��Y��t+��K���i����t���ZDz�����6�a��(��S��zc�4?h�zz(�z*4�����6���<I+3J�w���G�?�4:e��0�kgB���#�3q�KK6X]����\�:i��*��>����[��,0�-$�;k�����K��������y&
�����8tj��G-���P���Y�A���Y��� A����z�����Xe���Y�v��#u� �9����]�}-L"�tj���� V��/�uv-x��u�����I�#A�|�p�h2�0����\[���I���q������b�i�X5�.��v\�OC�:sn���g��D�:
u�k[��A8��M`�r�kZ.����;d&�R�����r9�-=$�g�%o���l'�<�M*��R����K
9��y��Re�"�����IK��m)],�*��lq��~G�
�J�5�kWD^jiC~�/
�/�8�G�$�4��mV�/�;�[o�����^Y������:����"}�{)�<����F�5��Jt��s��30�t,��D'��Asrj�3wI�(/C���H�*��U�:��n-����Qc��g{n,8sDg�7�WDu����1���E
����5��Fnm��,�'"����'r���e^e;���I�~�1=k�����/�hi������5����L��5��e
�G������pl9B%�Rx�vVoi��#�!��;���Y!�/C�h�p���������.K�|�A����w	*��J�G}���>i�P>����w-�x�D���a�!�����K�:F	�:�f�q�nF�!?���T`��xu�xPr�c`��R�<N9����H+`{_+-^�o�\�<:��7�	�p~��\P6Hb���eo�Vf8�t\6��I�|���B�+���u��uAa}x�T�K=��"�u�V��&�]���[�F&��� 0����;�Dc�_^XvY)��j�����?)wV�h�Z%�mS�������F��mwpe��e.7H�9��7,�?����Q���qc&8�,�e����|�_4{H��d��bD�t�����B���M�,�����^n"��<y��;��!����Ul�[� V�����L����~��K?���ZOH�l�yD�afo@�#��S��%%�mTk�L��L�y�O�zST����4���2����Y�#�=����4�
P�#��i�W�nf��K��M�m��������q��.�TD�����e���l&�z���L��l����9��j���%�D��-�=$�������&����y�z,e����3z(f)����D7_{�P�&.�N���3i����vt����S�s���.q�*5k�{���IdV?B��c���y�{��B����7=�s����"���l��35v>����d@���'��{��������O�rX�1tBz�b����4Y�����S��:h�8�p��#�� _��i�E��k/�|��	����91a���M��O�y��=
I����=x����Y����Nf��"3�?�IY����/ac�&w���%v��\��������9�g���b��j��T5Td\�T�	a��k)p3T��}1�X/�n$�#I��9��F�i���M+��R�A|��M���������':�����l��n�GN
)�=��Y���
'��h����F�B=�`8�����R������XP-\����,mC�Tj�^��C�m?�����{����I�@�����~I�R��� #�[
����!�%2kU\�.�Y�H��6���V���L���^�i����0�U� ���8t���:IL��V*
pTf
2���E�f�8_���i�k���5n�d�q��������3��UN������)q�Vi����k��XL��m7��J]l!������*js�@�����5�g;�k����K�����Y�+�i��n���t��J*�WG�A�(b��0�s�\h*	�"#Xs�Y.���/d���ho|��UU�����K�}\��-O��P�.�����|h'�C�$inxv�0~�K����8��d2��>GOmP������b�L
��}��@��9�t��vg#z��j�	�t8��"}g�<7T�#�
��;Z���fcdl=���B��V�:g��j�6l���vn<#�]��6_��3Z�����vM7G��&�az�m�r�9�U��4��TX��%�\�#�������=Iju���1����e��1)��i����Z���[&F�u5d���1�I������~>�
AF�:2l�C�V���	� ^W���G���F���A��S/����1p<�3V��H`���W/�p�h#��!��L����W+a���Ql��Q��D{i����i]�]j��=������q������?/��(��y�!�1"yw�y�k��F�O��^�u�q�t��*^����J=�/���\�U��\������`�>��oz���.�,�r�6�����r���r���
KF��4m��4?�-Qf��+�(a� ����P��~�9D�e�@:q�	>�0w��"���N��5�%;�����#��&y;�����#���A�c���J��
�Y���V��o��Y�"�C��Q:=�C�Q���m�p�����l�g��p��|W��HwtF�!���L	#�%���T8��-��`�h��l_R���^�/O����,����T��K��t�:X�F%�N��Q�3q�$��/��J����`�8'r���#�d/���u)
�������Pm��k�bz���*�����s�(BW������!�����c��y�
�*"$�E��x�}�{��S�k��eV�8��
�! &>5��r.]>���d�A��QM���;&(L<��\���z�L�0���6���\��F������]3.a����p��g�SI��S��N�&���w��)u��M;@��4U�
$����	�S�d���lY����J����T��c��:�C���wO24���Q�6�9��
	�]��)!��M��P�����L�z�������M�)]�����8eZ�B�&�V.�!�I�_��IXn�p������mp��2�
m�C;��}�
����Y��F��XF��*��lp�p'�X�v�}������D�.Y���}��e���u�^RA{����V�+�/��2RLq����=������,�5��K�;�����v����^[�91�GA��g5d��a����~���zH�a���b�s5�|�x��H��o�V?�+��: ������.��x�������"X�KoZ��������-KTO�a���9�
��$=t������G�<�n����]9&0���]Hc�T2��n�9�)����9�)Q��B>:�4K�7�8GQNM�r=���wW7�9~���	!�j&y�-�h��Z�(���;WA7@��!2���B���!�,���j���Q�s�i������	���PdT!�,]l�U�����m"�t���� �e�*���d�����bx��X�cqx>�]{c�~�!���T���<���~�H.�v���N���
D��k4��0��H��������K�)OB:{�`�^�c���6�������.N��4����0Ph�oVr�F���Bz�@� ^�n2���F��.������+[7��-,�#���� lFNS)�O������+�@pM��Yku�!B]Fa�����M�&oT������s���n�g��,����[Y�4�x��*������!���ET��!���u�J8��k=W�L@3s�V3[���I��z�Z6��*Cm}3�E�����h�,5]�t �J�tm�EF����58
��JV����s�iK�jjt��TA5�j"Sj�V�=��(ng�0��no>�=~�7jY�� N�6��54���1�����U���.&*���`�[a3+5���0�F�2�%��@c���e�ErA_-��YF2+V�<��{O����0�����o�5)�=9��yu�(!�� ��JQ�5��'�0c�E��"i;���n����s���	�op��it��M��\E��mTQ�����YZK?�(�E���l�PylVw�
����J��o�
�G��%)e��s����t)��f#����:���
]�%F+X�e1h��;��������Ei
������;"b��b�P�t3%9~�r;'�������@��C��xZ�0��#���t"L8s��G2�-�D�>N�R�N���LK$?�Y��G���K�yS�T�pg3����.����dd�2H`}S��C�a�')�F[��i�i������>,��!/����H�dx�Q5K�����[�����fUj&���Wt����8�V����#@k4������H�}E�A���/
�/�4����^
�
Yu�lJ�cj���F%�I&���abG]R�F(NJ�h!���+L�p��������O?mNT������������h�i(B-Da����Y���������[��W)X~2�\�)1$]uf;�A�\"��G�
���9���� z�j��|��me��Y1�1$�y"��D�����e�I�?Z�	���K�0��B�n�2�Y_��Q(��j�T��K-!��dzuc`D��U�g1��D������h��Q���G���}?�>K�?@�c`R�t���c�c!���{�x��S����HL��2��y���I��Mp����g��������������}L�^��v�7��$^�P!�y����CnJ�"����D;{���a�5�j�6-n������V��E�����W���BJ>!r����S��:���.��l���}�CX�#t��������p�>�aV��<yqH?�=�#m���?
� ���*����&��z	)�
/�S�E*�}�����<��"��E��������CXFM���+��r�b,��4�V6�� �T��a�&O@}�������]�	? G-�m�'&�1Q)g�A��[��Cv�Q`�&�QD�s���� �6eO�@$����)Gv��A�y���]v�gRKG�;L�>��[���������K��R� ~�N���Z���M\Dm��n�%�C�-d N��sa�mg�>w�>�Xl�a��q�prc�,F-�j�����p(����w1���B������j�r9L�����+b.�,u����~N�&�U�&J���FO�s�E�u��N�(�4���Nwe�y������8S�g�qfL���
��xQ�D�2e���9�I����P��vlU�$CB�u�����Zc�Y�g���p���Ww:��w��.�@K�CaOh�~@�
	m�S��LP�
��w�~�T��^���� V���"��zW�i����"8V��b����0��������O-m�B
������"����x��m�=��U'9�9w���%g�n����>F��Bn������'� �T�����B^�H�-'���?><=<_����R>��v�O���������������?�j�j��*qI������;��~h�=S��IR���}�����m�&����}��K���Q8��J�6��20��=
�r���e�
��*�|j����Np�vJ$��;\]
YR��*��^�������l���
	�Q,�M�R�<��t_��L�:��`",��zb�)��a�K�v]*���7���gr��b�T!��A�X����V{�0L��Aez��<L/�����
1�xv�:!�'����s��zU�!�{��;���p^��gT,�^(���V*`��l�`��"��d�2cCP��?Q|)&�ts�����L��w���h�&p�P�K���fu<i5Y����c���v J@��q921L�:�O����������Lg�J]@�_+����G2��X��dg�����B���z������j4��@E�6�-q�3����|�������0\�0��>��
�AN���o�����4�\}:���PrC����W�!.�����A�@	�����<W��%�L�r:��c���)>N�t:����cna�Y�V��Bl2!.���N����N���OI��A*���<��^jqb��|T����*U������E����a��U'TL�z2�Cn�>>r�Q�|���"~�#�����#A�\���"�����oX�HH7�F�G/�K��,�����2$�%���}+��������� ��#��>o~���d����I	�*�l�|�oUYVkz9�Vm�����
s��
��og�9#�l�b���0�u����u�=h��1��P�g��;T����%���t��"KW���d�����$`z�%����N7��,����b���t(�7���L�1�ju��.���L�v�F(^�e)V�R���-r�,����P����Z��,S����9�\����b0�%�BR1�
�I&$����kI���_;��#�����J�S?�Llg&��2�]6<R�� z)�I�
B@u��P����Z1s�U?.�~��O���fi2H�����!��\�E��Aw����l8N�(����I��H]�x� �c�B��]����	��]�y��;�-*�?�BM�����_��#��i� �+���>����a�ztn<��M�J������S���P����}6�X�]��`��L�a�F���#���y�ft$#�Dj���?A�p�b�@j�N���u+CFd$���q���c�[�8d,�M��|�, u)�:�z�����r�B�������� p�����E��!r�l9!�7-��*?H����g�����D���=O�^����>u����`�K_���U�������^�@@����r>N��
��VZt��@����d�p=����1��@Q�����|%�p�)O���jo^��Gi��_��TH[/d'�������]������Z�d��y��:E�s�%�����N5�a���EB�����/�T��d�2�����O�����.��]����a�
c5Nc��\85����}n���Wu���[����Z��C�N�h�a��:���)3���WN�=� ����k�^A���ss �M`�(���\�6�P���p���^� C��?�����S����'�F(�C:�����7@�q54K����3��V��������_2�.�"Qf�kA�^d�(�0�X�`��O��
�!2���_��k��Hr���+600$�3�����4�X�iX���c\��A�H�.�f�u�����7#2Y�b�""K�{M��p5�Lf�c�Z�GV�������A�G����s��=n���k�<loo�����\'���_e8O��n�k���I8��M�m��ZB��C�@��C��)�&8VJ�Y�U�a���
*D8$$��j'el��8E`"+%/��=}}���[:N��U-�`��\���K���^1�P6M��'d��4���C����lt���f��~M��|aG�hrM":(���3&x�q.7J���{R��X���/���QI��=���f�� ���e�L�2;��t�8_a�[�X���[Y���_��^��+��5p��m���������m������x�����o�n���m����(Cg�t�8��(�@le;O_��h��Qt�b���~�12:/������,�AN4~�T���A�j���U�.��J�Vj���^?W�X�%�K�|��c�9������E ��T��x�lw��#����}������;����YeW�V����L#F9)���U3������u�Y
d�q�!M�,25@�����8��w�
����+#�����M��I��9&^xu�\W}��D����L_��d�>U���yR�J�9^r4~;��og���588G�vK�f�n���<�x�Z[DU��'��`��W��P>�����y��\S�3/�m�,�*���t
`��p��x��:�0��!Tz��_�]�P�A�����[���;)F!PP|��Wp�2�R����:����:_S?���2+^�#�36����*�w�d��X���~\�f#�E�8�j%����%�$�n;6�Px�F�m��<c�2�c�'hpc/DP�$J�lK5�R��c5��ft
��nU����z����l"M�*_� ��Ru��0?]����b]���e������K��
�����:�T u&��&���F�kc��\��7%�f�p�f�d8L�h��	��Y|6"g#����S�P>���?,��M1b�*�Tz���r,Qh@����<�G���Cm?�T�oUo:�	g\����C�T���
���v;��a~���!0���T�#����&�0�v���.���_`JV*�0`���b�Lw����-��`�n�H�e
5Lm,����|�;*��y�r%4�1N�~�@B#N��Z U��cHK�^��.C����m@�jh:B�n��@�B�:�nXE|��p��5�0�B�R�{�>;���*����F���O9v��Es6�@�VSq��{�����~��-adE����:y�*�-�(�#���v�kz��db[?����B�����! jEbxD�D&
L�3�n�qKWlz3���q3,�]&�����^v[���:`Y����)�>7	��yD������)�/Y9@�/W���u�)�����0��<���q�n�ZP�����u���yP*�v�]�������N~}��=-�	�w�]~���u�!7I���W�|�
�C�����@��L2?�S
U�u���s�#��P���S�&�%���Y�L�B��<�(�3���4�G}�������b���-��r/������K�4kBD������|��~o�0P��Y}���a�)����G�|Bat�U�����I��Qv� �W�Lbw4�J�
1�5���Keen�v\�����@E�r�G@M��d�����o�pj��/�h��q���d��3�
<m�B���ef���*T�PB��,���,�87g�A�n2��`�gW�.��&C�ug`����\���K�$����zn/B
&D�����%'7'}�c�f�'9CNE)	D��������8A�?2X�;M�9���Px:[C���Hu��f�q��� !�F���9Uw�lCh�b�l+V�`���&�t������T`0�P��R+���pS������$�S��$q���2���H@�`��rjhr(��W)=��h
&f	�&v��]�9F(�[�g���9N�	���j�.�)e����D�
	\����Y�`?D��$�J�������p�S9-����VB �KQK%�����@[�����FD�*�I�)n��K��j7;��&	�������|���)���^��2���6�UuW�����X��_a��f?V������Kb�p�sP�6c��@�O
e�V���
3q	���(��_.�%Z�q<)@�����t@OA����iP;�K�V}
VC}�4��[X�{)�/�[���J�zz#��v��^�����2����z��:�b���V/ks=��2�j��������5�P����@����^
_�.s���L1|��W��v���+"lu��y���A�eF��[�lB��t���lE�7��\b���?[y�uu��JP�c�h�2�x�����������g]T��JQ7�.
������1�A��Vml��[�S+c�~�6{�v����
@sdm�.YX�C��]����P�>u�U�����+���	q�	���C���y����������o
]������<�F^���*8�cd!��G64*NY}T���J8�y_���<���&�NlC��9��3���Lri`3@\�y���IVX��4��T7qW'�pyQ���!�Qa�����x$d$3������F�,bs,�����;��pl�1"��������.�����JsZe�qM��A������t�����������uB�
^�\�B��y
�J`��0�0���8����/�G���$|��M2���B����r���c^���|�E1\�a�`~�EqRZ�i������.]c:��Nhe�,�
X4���\��,&-�S��;���^�D������n�rD�x�� �0��k�8�fUZ��$�Jgs[��e�k����v{D��Z1�t���Y|�� �y��V����P<<`�t�>���BpA�Y{3�Q�������L�W�
9���������S���_ewfV���Z�7��p�*�TO�4&�
;<����w���#�>q,�O��z�=���Y�;���5�v��L��]�q=%�;�*�f���^�2-�>�[�(O[Cl����������L}W:H�,7��az�r9������Z�< $��
V)�W�.:)�d�h�3
����;���B�����r���Z{}�<k�M�'��B�	+T�qni�xR�������?�U�mm�h>F����0Hs{���G�#f�)�2�AJvP�pOarP>�b�)`��o��G�vS���}��;�E?~��/@T�����\X����1���W�-���aF~��[���F� ��NKC�8��6I������D�����<]F~�/K���d&��	2���`"�
}�ra����"i���C.j�
.��d`-����Z(��
P�v�2kU�;�Q�fD�&�m���K�D=�SL}��U��L�����[����Ca�����'�~{��Q��Ou�a��aED(�^��!�@�	wy @���F?����b�D�����^�V��,�+h B����X�����.Q���;�b^k�^��y�M,�V�#�N��"�0Tf��up��Q��on.qDa%f��$��T�����e�.j��|`������_����??��Qv�qS}[MUY8�l����7]8��s6���������f@L,�o�~�_�����y�bU� Cx����r�`��-����`�]�}D�|�|����P��%������e?�"Y!�(F����VnW�Dym��e��c���+�����2�������`}�!��P�.5�`p�U�����Q��_owk4�rV���Ja_{�]f��s��i�� ��������Ck��|��>V���r�hBH���,>G����������hk�d�@�_����y�����\A\�]��a�}�������x\
9����V�y@�bM��A��[W�J��{��wC���uAB��vj���6!�9���\�1�	F�O���������<�zK�C8�R�2PHV���@��j�|cu(��	��0���
�K\c����`�U����!�o2��t_a���w5MM�y3�!�1tS_T����fL���\`��E1��S��9�o;���	GCO����S��M�)7��_c����PO�)8������������S~�|�����5��k���������������8�+�|���o�\8?�Hym�Q$2(p��a�@�AN�**���Se*|��>r�/+������@{�b�,��2����WP;�����U������A�q��D`��uM�����v��f��������-�_�b����Rq�we�����n�oN��{Q��&��]?fu������=��PJ����!���V��f��>�8�����x(��/_�XU���)��\�j1�t����[�G���%6P�_V��GD.E2��2.���~������
�������v7������8���������?�?E����W1s�}|��o���m��������?������������!og�/������nU���GX���������nN����K�=�K�~��@�-t��uC����g^����#��<|e�D\:��:I5n��Z����eD���l�s~�����^��7�����g�����s!��a���3�~���������oY
@���l���8�����4��%������c<*��m(��{��,b&�Qt����o��5_���t�v�o����k�cq�qp�����S����a���|N�*���O�-�.����1���a��,�&A���yLsn	�G�I���"���r������H�>��=Fg�9pZ�����������l$���)uC�g��8�������r�\�Y�d�F�������8�kM^�Y�w	c�8|-9A;h�����S�;+.r�62�:�S~Q��[**Z�5�������e�P�_��W�������s/>�Q��A��b@����p�F�ti`s�-
�^0�d��(|�@��P���:+��w������[�'�V����[#�����u�g�'�������"�������P2���`��(�����D�r�W��m��\�%�)�����G���������^���S����d���G������J����������S�%wK�`q����*k7A����������h��A)^�'>���	q���	]>�;N�\L��r��J�9�1m�y��rn`�)��P�cD�S������}���	.�x�����h�v�J	9�!,������
��?�= �yW�J������������V���W?#��q>����(�NIW��r\c/��8	������|/�H�^uB��n�sN�{fnOtg�9S�7���_G0��7�X��o.�<�bS�U����uH��w����tp�i���E��m��fL��y��Sv�'������v�V��!���gU����c����.o������3�#:��4�w�O��&����:�u9Z�4O�\&��R�
c��&��z&s#����0�d������}������)������Q���
e��-\�.4-9?j���^���������qx������Zv�kp�r~�"��R�A���������Lc�����&�}���D{P}]��v���:����������z�WA �j�����^�`1�C�>G9)��9�vA'�EK��p6�����[�k�vZ8�u��;kfj����g�(�sY�`=�y�������A����U��ub��e�*��9w�	zp����]t�Y'3�����_�Co��R�aD	�X9?����������:���h��q�JW)��X�w��V����"$�S@�!Sgm��7��2��-��_V��p�88����A�S.9�gn@^�fxG�����s�I<2(_��������/�Z�Vb���I�V�g�%�h{`.�%/��D��P?�d����+�V\5�f��&:P�"����7w���\vE��3�f�+���
�2�o��E���8��R�	�����O���^���%1���������P	�!+�=.��B���'^�1?�:9�^�{l@�����R���#q��De��J�i���5��x�����c `f�?I3��P^��@��z1}�O��Pd�&�%��a���	���*PMde��s�������|EprX��~n�]_��o��j_�;1���S���*M�4���'\'0�M9�#�q�am��;��}6~+=)$�0|������ZC_��;����^�L+�Q1w���*�c_��t�Y�Eg����6����0X#�+���BJa-�����h�hp�� �"������������Yw@����3����T��	g�����:�X�3�x��U������o"��S�V����g���ah�
��*���u�C]������r��������un��;%S�0/5��z��>wF0W���U�=ko���������{��:���c���o\w����\0+�-�KjvV���J~��j���U�=��60.Q�L�v�������}���ef���%��'2��@���a��:k���?��s���"? ��Z	�
YtP�3�x<����?���9�J�V���&8���:����m��H�-o��>)�����6���*�-<.���
bm^S�����.�T�u��c��^)�wu?\V�����78d��$"����`�`�*��u�$���Pb�c\;%����TT�4m�~�2����U eB����Bc�(�`i?	�6����*�Z]]J�����
$DOhw^�&��4G�eL_;�>%�G���o���SvT��4?8.�����?�u%��I�q�����IQ��������sv�p!��t\�>O{A��V�Q��*H���J���1��++"{��6.�L^��Y�.�i��������YdC����u�n���B����|�n��H�ux�>���1>"�M��6�����R�6�|b��D�KumSC��R��[��5D��Y,�k3�?�
WG�H	l������ oXTtd[L
�"@���[����M�g�\��irs�h1��L���?%�uQ�x��Phy�
u|t������Qy��� ;-vXW�~�����0�z6���E�����>OaN��6Ne/y��0����|�u!�ts���oK^,����l`��������i�����}2���D$W����=�������835����l�n��{�=���svV���T��2�$TYP�P�R
��OdY�h�Q���m;����0{QE��9OL8��
��D��K�'p�iE�k~�����R��G�� �� (*���v��j{C����S���>r�&��N3����GQV�u�n���r��B�3��k0<m;����������W*z3]��;�^����d��
:;���m����-�RB�fb��� �9�I
	SKi�1iQ|}Z(���� �����T����2Vk�l�jO�WK=�����������������/F���VW���@Q
'����<l��=��WX����U����l�����2��.�s^3�.��]~�����������$Q��ta~�^�Y�m[2�!m[���+�Q��xldM���;h��L*��%��7<R')0HChw{���]��EV�I	��
�{���������z
����X	8�Tzg*F�����0
+��o���������b��]N��s/��H������}W��H�&"g�NM2d�\��'�y���9Q�p8n�Bkt-^�s.WH��}���",�i������K+����q�%��W��|����J>^����s^��;�x���qfb����k%+��e���*.���8��q<���o����1Y\����6^��j`.�Q?����Iz
8M�XB���{��]��(i����S�Z���K'$V�HB�T6V*�%#����hLj]�cF�O<6L��
�'�G��9���a�x�Y��F��D?�U��9d����x��mM�S�f�s��`�\Ez�����}f���D��!/��#�c�'w�'j�,9C�#H�UJ��4�������Sf �����M0}��a�g��h?"����%��@��'��C�y����^
RaB��A 739���m���4��BbS�|[(u� ��qD���H|��i�c_A]^s��`�e�l�*��.��8
��;i�q��}&��������wg�)�&H�0�\n�a��xy9�
O�49�G��7���u�r��1!���b�0�'���,��GP��e���FI��q+S!b&��U��w��z��xm:YB���WSQNH�Q�/�o��h���Y/����%n\�>��u�^�I&��G��m�aDi�Q���%*(6������3��_�'C�����x�+���"�����-��*����G�;\�y�3��gx�aZ
��+����:0�8����������h�L�l���/��V���F��������@���L�e��Xh1��NNq
C����m���1��\X�5qSz��_�����8�����5Y�h����n]�#1�<j�bwr�{�5�\u#+kNN�yE
&\h�����p��Y���+��CR�{���At��PO���g:�L,����0=��N�������=��b�7��}�8BZ��K�/G��|������	����f�q��{(�:y��e�|c&1!#^y��f�wqv�u���C���q���s�p��	M07��Q����\b��Q"�UX���`�VeW���zp���ql�|
����>�*�����y�9���G�����bgW�#�?��,����T���D����&�s����x����\k��Uz�'*`�hg3����#(vDa��������0���J0[A62��:Y2SO���������s�~B20�F�6��B)�uJ�����GNj�wg��E���8��I�qH<��5�y��t���;g��
��K�_f� +���/�Jd�8\�������N��<���{�~0�G����}�O\9��3);�|7&4�Y�|b���`d�~�:F�(�Mq�������]]��i tX�{�S$Z��#<'�b]1"�wmgB��������C�m�T*����D������FaJ�)�%q��?�}�Yy_��OB��\>�	�t��7�5'�
�d��f�<�`�H���z6KV�����PMC��34
0� U�-�`�e�,/������|���]�Q�L��P�R+����Z+k�C�@����UX(S��(
�
���z��#�[����u�L������`�����P��]�f�)o�w��	�.F$�]����+��&4p����	o�BnJ8��t}�$�v0=%���������A�n�I�p������kA����PuH^��M0����+��"�8�Pi��p[����g:#f+��z$��*'Oy|5�eV�9�����	����p���}��99���O�M��j�[�k���x�!5g�`F)
^��fz�:�\�������]<V/�9c�Ysx��8B�0;6����C�xU�6���W���uX,x���')%-G�w����rP��;���;�i��,�����)#Eq�po���P�z4�K�����1A�Tv)�6������W_B�������PEE���s�#S/�����&���ht�@+�3@�>���kg�D�: �G%�B�9����������R��q���k8�c��%S��Fu��]��'Y�8���l�
����2��9��*t�N����Kv���X�6�}��>^OZ+���&f��+�������p��up�oY����j�Q� :]�S��Li��jGt���z���C�������NP�`��1�
�t����&���~K�'U�-�xSA�G���x'�H���M`�*.2=F	)���U�/�XA,��b���"p8��{���A�xrc�������K0b�q�wcc7��q������8��DA��
�a$�,d��"1��c�.��c?���������j�P|W�����(��A$rYb�T�s�]�����H*���>R,1u��/������xA5��aH�9o��C����S��K��5.�!�R�uM���au����R2d�@��)��YQ/��k���IF������`���[��Q�P��������(�U�H��HB�F(��&4q�&*��;eD�*����O��P8N�?�>o��Vs���!L)��\��@���$e�7y[���lr4��S�B=n'I�x����e\#���|�7���W�E���|2r=���Vye����/T��fM�V��zW]m�(����D�����uYy_����c��L-�C��M��>���Tk�P�T����G;�	W����T�V����8��XvA��1�Z�v=K!��2,�|S�7���6�k���<$I+%��W��]�hUTm��SL��V���s��>����[
����{�	B�����n���iu�9��^6T�x*oz�.�a�]D��``I����=�I�W��<�%�DE��v@����Jh�b������_�PN`��,%�hl�p�!3�t�L�y
��RP������m��F-���[�,4����n����F�?�hU�(!��u`_���J�0�)1w�1�X��V��38b�a0��L�����
���B���[e�d����� <3���N��Pbq���,.$1�ei?O�Y�v(������j�����M���/�L���c��YX���/I1G�� L(c/Vd:�3}b���yl��T
�O�|�_ZCD-q�q�U�,�Y�9�@�%M�����a\RLa�����=�[���tY�a�K ^$��47>�]�i�l���r�D���)q���^�� Z�b���HeC'���t�v'���qj��;E���b�A���p��.#��-`�G�
SA�^���e��Z�������������$�}J}�8��Y�3���h9*�Qq #�LU�K�}Y5�,M�l$NI��'�t.�7r���$���Q5~�R&�$C}VZ�����A��M����
�����r"A�������%�=�>������'Y�]�yn� 1%�v;�);����]�"����u���#������.��k3i*H��-	Q�4N��G���"�n[�!�{-G�����vx�?��5�"��qvJto��bf0Z*�d���-�"��dT��t	c��w�Pp��
Y�Z��q�N;d(VmN�����u���t������
����=�V��{��wvx�i8Y�����)8�U9G)�1d2�j�����;B\&�<[�Sa���n#P3������-�����@G�E-��\�a�*��"�;'wk*�wv�$%&;�l�S��D��.�Ar���1�����KA��9���Eb�h��i�a����q����Rv�2�;5���� ������R����_BG#�-��\��.���Y�+r�.�������&i�12/�}<D*�sql�DRZ�"O��V�+X�&��gdi@������:�c���N��/�X�G,�d��������tB��x��������3�d��8=l�������y-^�|�����6�v����Z�D�*&�]ER���/�������_(�A�	s~V(��U-�n)8�v_�I�&/�r���w!�
�<N��Q�U����L��$�AC�GXX��R�Np��i�	<}b�'���]MRWA�f>���|<�D�D.QL��������8E�h�5���.�8��C������b��	Mq���J�/%�;���B������l{�e���K���P��K�z�I\�T�<��4|fxr�k��2�:��<��T��"	]v(�E�<�����GHht�Hq�L3q0Psj����7���(�7��bc����.���p�E��k�l�2+�y�,��j����C��Lx�W�N(sk{��{L��Y����$��\-���]����4i�"n�Rp�I��E/��wW���W2�5���G�M�9�@����GF4$�Khg'�
~@>�9��8��g��u��"#��#��^i �m��DH|93}�Vo��������@��@B�uH�0@��]vwHoJ��;�62��������<&Q�cs�t�������/H���7��d�jf��r-�u����%g��������>�D�qri1��}+�#"������nd��2�u��h{9������������7^���A��BX��L*B��L���0Z|�i,��e�c�2-2��  �g�%��p����-���x���*}J������#Z+��5�"Q(�>�X�HV>&<�7sP��x3���&�Dx�$�zC��$H�k������?��c`s�]}�����RW�����e��{��~Hv������#u{��m}��1yY��8:B�������1�(�����b��G������N�������k>�1���z8��o��N�e" ��&�DJO�Y��^�������;�Sxe��*�:�I;:A$(��}<�e��I������4�>�n����7/x��i69�o���9�F�z�$k��*�L��{%�s3o��_���xm3mm��3��6Qaw��U2E����'�N��{D0����������������I^���+��-	W_�

d���Q����B��{�v�����+��� R�O�lS�X�-��nK�g��_���@b(��a����vM�����_8s���b���Q*}Kh����d�P]����z����"�����Pl���D#=�X"��93���;
�����d=i�s�KQ�����4�a���l*'���0���ML��N�r�;��>3���R1������!�C�n�w�l=��AD(�d�'�/�c�L��Xe
�����Mm���w�m ������/�;��c
c��e�Q����t��V��|�.�e�x8:�=z���V0��>3%��N@�>�KIa�\��V�Z|�+p�`���-���T��$G�������KD��������
_�����*�'�J#Hz�2�U�Q���mI���Dq@�g	H�;&�Q��Y�=:���A�b�D�Cl�(:-b�j�[Cl�S�$�z@��2#<�����\����
]V���V�d���������z��#�a1�_���3Bq�~���:-ez����'���N}u�U!���[���x����C�8HF$���T�3lee*�G��|y��������Y9hK���H��m��K$�a#q *p�gP�E��9�,�v`���
T~��]Lm�#���,���L������7�O��O��~�)�]?B��������k���k�-�U�����N�x�le���9�}�,A��k�0�|���k<�Z7�;V2&&�D)��kPk75�aM�`�	�h2Yp�a������m����"����z$�FIm}��d��]�Se��7ov��j4�v;������p���u,8)��>�������J(���)�:�(�eU�O���"6�4Y!#��!t�;�^}G��w��RB�y��N.�����@�N�V�����f����e����VIB�pjh�����O1�����~Y",;|a)/KCM��E��V�+�A�"=jSH��ZF�������V2����#�y��%TW+����!,�J�`��r��Zf`%�j���KSn�6,�
j���k��[��d���+��d�
���M��]a��"��XL��
�� ��,��������Hh������*�a��:L)0A��!��P� $��>��n�
��.?���S��P]6�>D(�N���XG��Y��'C�/K
*�S1^����_����M�Q�>��<�0��~�x�x�Hz��u|K�����v6D
BRA�*R�CB�pvH��w��gW=����b�a7y���bOm��7G��U�O��XH��Sx2�? �B��52
J���6;#�T|Y}��~��QA����"�I��37��"sZ�������%x%-�}���e!�F��ue��==�"�$�|��T���k����%�N���#+_������:��t*���i�F��|���(���?"��R!"��*
p �-{�h���%�J*g�0��
#g�Q��6��������:�����c�����J��b���^[�o�z��)��X��\����s"C��mh�w����m����2�&u��xX�2�������RA��hs'������(����#C���|���	���.�B�����.���Zd����O�U���a�����F��n���lL�.������������Q
���t�����	Qp����z��H�+��+�B�x�
I���
&BR���&8����*�V#���AD�I4����{���Ba�������v�~��fG�s���+�f���&@���J�cX��I�u��3��a�0��#��t,?�����z,��q�_���[aBxx+,�y��n��`������+�`C�Y���V����F_?�U���*:b(� �)�h'+���y�l�'�[h��#��O�l:d�:����� D+x*^,���j�-F��	q"AW�d�l�n�`��U\��U����A-c#��(���d8�	��1���8��|����P��)���l�M&�|���a�����bUou!��af����uo��]�(T$������+�b�t�[��x�6Q�������Z��je�O�H��^>�l����#��	�����
�)�Y���=�N�+��^J����dD(T2�1��

�1�N�:��yR������GQ�P2$L}��k���5��30|2�>��K��V�����\����!�2.r���vA��.��Y�3E��G�m8@�*�,���1�f:�wL�[Q�(��T��V�^X�Q���'T@��@����Mx��	�[6a�$:�Q�/k�aj�c�n��j�=�4�3v�����:`zf&���GPk��w����5�UM��=����^�6��^���&6���D|�|2�,��W��.���ES!<I*��[*��1�zB8ED���S",t2��c�*[,gaV��X�;��f6�O/f��i=�������"��B�]Or6���J���y�A� 
r�F�v������1(�@h���c�g� @����!IU,e�J��B6��#���R�D��(�!�Y���O%��$~��"v��*�ze�!�lu�LQt%z�����c{y���e���<�ouJCR%�z��!0`�;����6��	YO^�c�~���_u�����}��K��}��H���N5��-i���E_EB��2��O|��:%�K%����<�cBO��<������37Q}�
�k>AG��z���-��r�.��������.�}/�A�����m^�`l�y��c�����g���Q{���Gh����9@|eG�!x&r������ B}Dc�iAV�)2��p#��F���]%�m�*���������;�"��a��O<���*�~f`�63���8>k/���BaK�����f���+�>(�GE�����
�P1�bT$�����?�F����x���`w��C��d �\����F�d�0���#�Zh��3?!'4y��7&(�B�����(�\�

N�^�Gj��~
�,���b�@���O9<�Y`b���U�`,�~Qd����|�����1YP��Q�7���bJ
�����p���d�Z^��G����MF�K����*3��-�DlJ����,v���`�)�Ex:��e����h�.�v����g�z�hqu�
V�'N��T_�op�:����2�[�j	B��**�������z���
��:C�&����?&m���<BK8��s9�:wwp��7� rPKy���O}"
�t��]�+��:a��~Mt�����P8P�.m.I�a��:�A��w�x���7!�])�^
6��!�����u��~�x+��C��"���<�o��*�����Tm�� ��wM#��Ep���P����y���;����m�x����i�5�A������Y��ie>�m�����:�&�j~���.���~n������f9�R��tQZtid��n]���$_�-���� �1�@�[� D��9P������iM���l������ �qqs��2���"�2�y���`���S��i}"���+��Z�6��`�-L����=���m;�I2n�9`����E��.�0�~3+�Or4��/|k^�i��"c#U�/�k����@'����_������ct��4�\�]����E��42dF~E�{��j�����������Q)���A-oN���a@�c#t���>:��%5 ��Bs�D�qMf� ��A�+�<���>i��M�rS�����D�y���A���0�U��0������G���3�=\�t��Q�u���8d*��w,�I���Z��x0������$��#�uA�3�]��,wJ���U�/����Y=�L�3������I]���A�o�xd���oa�;����P�P� V
���O��n�r��� (�]keD�=����an�w�_��.�A�%��(���� 5��0���*���.��	g>emh��/,!�U��7�A������Z�iKV�w�Uo�\-��OciM�k����������H�q9�K��6�g��~@=����PR�Zq�.k;K`Ihe�k��zp@�v�C	4C��0e,P}�����t��0��Ys�80���Je�o&�r��*����W���bY8�TaUx8d|0]�Q��8	������u�H����{�V�D����X�g��I�.�Z�aa� ��e �g��V�(t�2?�`v�7O�����l4�����<]�]�/K6�73���h���)(#���aD�C�����1
� NG��:���)9�U�6�N��,���ZuH���gaq����h�B�"(��4����~]������H���Ai�ca����0�^�M�d8������}G������K��`&�N���aaij��W��*���J��9r0���Ww���Z�b8X��E	���D��W���XN��� �\��XP�g�T1��h��c2��]��T�����B�z<\f��m�77�0�����@aD'*�@A��!/�s���v�w'_��#�B���C��P���<��2��e?�"i�('A����FW���V����U���g�6H#�T��c�^����tMcy���^���	[s����������Ul��;p]7Z<A*,2���.��Q��,'bPy>.��/s����B��<>�y�:?�(y��f���]��^�l�8�e�NC
"\�"�������`~�D��y�
s�H[�V�)�b������-T��>�u�#���Z�;��X���DB
"J��#"�J�u�C0
��X���Boi�������� ���|�=���c�&��7��X�yQL}^|��>�a��y/?��q����*J;�c�h)pQ1NSq�������w_��zy*�	}8��������h>����K��t��b���M�����M��c��Y����6T�a�����3V��'�3��k�G�Ru���x+���AX+��	Sk��Q7�8��@Fu���g�����~���_�6�x�����nw�����S�������S���A����WGM�}|������ys����?����������T����}��V��_����������kn\)�/�����������Rw���l�'�5|�����2"^��+\Ov��x�������w�:�k2��������?u2[=:����9�������1�������R��?�yu�Z�����]�?�}�S����g�}�������x/�v��'F<���qJ��/h��|�;��kQ�<K�'�MTv=U���.��$���^���O,v����{��]���h�w}3��u��_�/�ESCX#��5��z����������^�P�}�*�z�Z`)��������*U��^;�����,�M��������G��wi������7���o��}��W�`�b��x!ou���7*5�QG[})��?�_P���r��A������O������3��{G�����c��������������	���N����<�>��l����_�������������^���k�����2����Sl����cnoN���_���[wS����?o�}�����@��v �����7���?�����������!
@V
����Q����
���p�����{��������~��-�w���1P`P�??~�Vy�:��������W�1�eU��)5K����G7��r�e�a��<(��.�Bw����i*J�d0�B
��(�.�B-��(���e��8N?`� T���{~z���;��������l���������8x�9����]�;�f���=rP<M����'���1G2�Y��j�P`+Q��%�)��g�/��
7�'��}����������-����n�[V�
2��L�{�;l�m��Z'O_����e�u��}�\{��A_�����R���&a�;��t�p�X_���]k�?=��Y���M���_Z�~/�}������j�a�W���q�a-7�����������P����}�
k�2�x����(������9vo{�1
�
��k�#r?h^���d���on��������73�I���Aq���Vu�����?��`��%|�;!4#y����]�1�6���r@�9�ka�[����F�v���%�Yp^)_�����KR"+��{P�%G7p�,����@u�Ae��F�O��a,1����)�~N�m	�1�f�3#�Kf��!g���3�O��Q�g���)3��%��uS�e�qS�Y���b���YD�Y-73O�T{I�}fu��s��L�sW���uW��~3�bP���x��Y��e����2`�b�|F}s�	���x_�z����9������Y9k'Jo�L\��V|/~�V����:�*s�� ���?�U`(N���dg�!�n��3�������v/���"�'�|���>�)1�vl�|�{��/R	s���~�e��6��I��[�(�k0����*�F2���~q�;�j[�Up�����~FU��������/�S������'L���p�`�%s�����=w�����BP��a���\�L��F�r.r���y��W.f��?�s&�k�]�/
��9������U�-�P������X5���[����B���,��D
��:x�Y/{P�O���u@fUIjVeHu���j�N��y/���JyX`XU���GkV8r�n�y��5�4s���{�����vy��B�J�U_�i��k��uO��d�����@�p�_Sp�������u�~X
�hNvl����j�{�:u/|��q��?b�����:,����A1�-��5�d�6��.�n��/�����o�V}�vx\��w��6|��YM�������C�?W��T���}�	�E8&�Y7�r����aH�^9%��:�Q�+������G+��b�@���L��V�c=�w-%���*�h��B)�Q�`t�������a�|T�d��`"rt�������'o�u7*>��"�d�������`������-
`A5�{"(�����b��@�o���I1�E��2�N��k��>T�������5v)�������7�6?�Q
_�\����W{V�\|IX�&���/���f��f��f�Z?����V�L�:�.w!:�\)�j������d���_#��!c���m���G��_o��}I��J��~^���������~	G<Vy�}>�w�t�:��0xs��Fy��m��1��^�q��a)���B
���������t7��i��K?t��s�x�~�a��gS@�}��c�P�M��8����	,0\*�r�(]b.�F����ld��)S��N'b��wn8OH�t�R�����%�B� %��}i
]�r�OUy�����LG~cX$3��*k��A����%R�b�
l���]�T�B��b��!J��u7'����I�'�Jo����}��-�`���*�Cfr�u��PY���$�?������b���/����uO��Ix��%�_�-���:�b!���Y'�/3s���B�����]���.>uz�p
�
��M-����Z��;���I���� �"��x�@�
j>�-	x����E�&��7:��`�L���v��?���^������*�Q�Vm��Z��t����9��p���������O����ryb�KBw��\&���Nv��8GW���N>�.N�2�e��G:�C����%u����.�`�]W������-�W4
h���b����O�qZ���XqV�����rz�]R��z�M�V��U��� ���Z�o�5�M���?	&����i���(�-�B7%�cK��)�Pj�\X?'�G�^�>���);��T��N_��<��O/���5��z=?���9 ����]��nR�6T��`*|(X6�����>rO��JR��A-�f�l�:q)�
�Z���-}�),���g4�������cb�\��[W���}����.������f��������U
v�vu?\��X�P��[f���!e=��%����k��V��00}�pGe��/���V?k�4�wE[f��
�����*�q�c���y������H��������_&���;����U��q����0�f��1C���fo��\�A�P�V�6u����2���k�@�C���\�%8���5c�w=t����D^��v&��;�#$)�3��Z��w�����z?�Y�����Q����i"Z?��W�
[�������s������Y��������8��+�3p��� +WA�����u��	��Z�z��
^J�������S�����(��,@S*/��>(���PG�f%�	��2���V�VI3�)������K��S}1��>��TR���"����9tmg��mHv�0����_�����i����qM&�|���5���r�VU�/>�IC��7����-���a6G3�����' ?�bM*U`��Z�vu%��q����J����$���Db>v��H���j%=X_&�HO��>59���t��������I��]b��n.�HfW���8�S�Ox(�ra�������8��} �����<x+,�8��) P�vl��%V�z�enMum,�������I�����g5v"��Q��R��X��yA��nX'�-X���n��ihB����w�f���] _1�p4���4�9Q<�!�N��uO��)�T�[�G�]�C���3�W!9���������x�V
=K�S%%m
�C
�U��������FD�X���� �����mO����y���_�1�*!��~�}���4b::�uyy�j����E���~IH���Z`K�_/�T��H���e2�^��'�
�-��g�/M��l�X��{u�I���K���3�B������%?�p�T�+}6�����l��`��
<i]G�pQ�x�R�w84\�#Y���P�}d�����p'������(���[����p��L��K���r����[�!����F:���h:�Z=���H���
nd�0��w�<Kw>�h4���`]�VcAxuMYOw1k�]���#~<dGC�oI�S3�?crv�qCMt�P�����nN��f���O~jd�?ab��:~Pw����-�RE���}�����kV��/St)�[@��b�����������
L+��r�����a>�/
������8{%w�����I���S�����l�w��h�����C*?.�����=���W�Yx���8>��:{_z�;�[~�r���n�{)o"�rPj����
_gTm�k��
�x���n�ty���9����u�� M�k���{�u^
����`��'v��eE�U�,~���z�1�!Y��)~�:-|J��76�c_��x���+�4JIH��V�YG����� ^4�(�{��b��m��g#���E�y���$���8yt;|0���i@��n��<+�(�r6&Y����m���:��)k��Z��Q��k=��1h�����j	���0��o������`c����we$ H�_�q�0�.�!X�|�+d�2���]TW���Q�'].��W����������$5���}���n%|0�QTyY������a��:!�-�y1�Tj� ,8���*�*E{��^��A����_����4�>�V��p�ip�"�c�,��&�6^�s��2)W��R�{�[l,���U����n����s��OmdD�e��e�	�v"��)�d�����1/R�]6=f��~�����[��[����MJ����������g�Q�r%j�L�"���m.����}&o�h�-k��f�fi��8`r�Z�>�6������K���I�5|N��s�����v��a�Q�c7vE;�5�]9�q�����@Y������^W#:���J>���'�-��Ng�(�X�b��oz������dk�U�V���!��3���C�W.ug��qoJ���(���IZr
;S�_�?���s��#�{(�b|p��M2���oJ��7�d�R�n�A!������O,�zu�*�%Y�C�
V��0/���/�.�4��� �AV���dhse4�|S�����.yLs��gv��{���� ��pv���zk�<5g�Y�����?���$�Q�*K'@�W��*V�l,Ki��5hGFK���������a�������`��r$�����%����#,)��9/^����S>)��c~���`���e���Z�3gR����������9���Q�pqJ;C���}Z[L�_S����]-�mY��d�7�����������r��N�f.�I�)�/�pvq2pj>�������A [N������f7\0b���;��f�����MeHAfI��� ��]DWz}C]<6��$�k�M��� a�'S�~u02��~7l�:t��@�8�PKu4��B���O#`����R	v�
_����S�?��'�Xz�B-�P�g���J01�������Y�I��e�����k����n��*��e���&�s�YN��I��L�4��&�=�a���b=���5q�����#�w�C��Y��OvL��d�B>��5}���!�Qt�8?�h�+F2���#g	'�E�$i��	+X���1����V�����-7.v|-�G�3n-������)=�1�~Ihe<�5��Eg�!��p���'�s��<3���������KR����uR���5'j����:���
�Sh��S�C��v#��f����f�k����MY[_���B%a/���?&|�*�ME��Bz�����*�0vG����������Iw��Q�X��>�a$���x��O����x��b���bJ��0�
9� �[,5e�TW�A�3^��M�s�0�6���-�8�>�j]7�&
t�t�s'[r�1����`d������P���V����`l�1-@��O���{}v9��T(q�������^�<s������#���Uk��9i�����9p�f�(�y���{	����,/�4n�H�Zct���4�1n����O�����g7�������]�L����kut��F,��oJ�w�����'�{��jt�R�H�	%�g���l���JN	�����q���
��3Mj�]"�%�q'����t�(�N��yaA�h����N�!/vvx���2�G���V�����Y�4�@PE��;��B���i���Z�Y������p�f9�4�a�-I�������9�CR�vh�^���c���q;^��(�ho3�`���7��OZQ<�|>JM�t+<�H)59%����'��x�D�V�����y�8(6��|Bb�C
f�i`
j ��
���u�L���(�A�k�O$v
0~f���,a��c=�Gl��0\�*�0y���JR��n��a�h|t)i�5Z�m��VB^p�U74T=nX]/�l8sJ���0�����)��y:��_��;�)�r�!V8:���(�5y�Oa+%�:1�;C����<O��#��mb��������*
f�l*�>�7U�/[J$�k�[6,������~�n��Cf��}����I5��Pc�L[B$��0,;��cX�>|�t/SG���wB�?��7Ca�*Kx��"mY��8�pi�����(�Kib�}@��0>�
�����5�D�~�^�6g����TGK�PGU��_u���-�����������
F��^��v�Cr/�)�eM����
�<����yh�y���hC(��=�V��f�.�)dK<
�:�A�C��%j�Z��F'�?��(���i?�g*��2��y\�k��������3��)�Z�Oy�T�����4T��2������J�s������$��e�����h;�����YZ���*dk�
2���w�L.x4A�'�i�O��VJ�}�M.i8�;��,y�����L��oK�N�e�<N������e��\&'��W��)nD�<�8N�d	�����Xvs�L����~�	h��XHy".����{������.��wB��B��ps�C�����R=:|:R=�k����:+@�
�t��T����h�9�0����]��}��8��!��������C=���+\����x��1|��E�"����YC��M��P�3lA�&E��,#�;��Y%~>.��g0�+A�yJ�*�������4(|���"�{��LX�����c���o}��p0O�Y����^c����"�N����I����2w���!(qJO*���U�����u����R_�i>E�(�6���
��y�A�9��x�95�B���m�H��YZq�'Z����Y{���q%m��K+	B,a�[��S��B�������N����x��.1��zB�C'f�Oa�0)���Y����{?a^_�����H<���q�e�'pa�N<��"K�c���L��D�Y2��R�jQ^kd�'�s�*�bt\\i����l�N�#R��F��M�6S������uB�@���Eq6;y7���#��A�"�!���yR����]�f��g�*�����������l�J�U����j���;E+?�^����G���P�� ���z�,W���`�)0�����)�
��h%y�M;����4���c��;#q
�'V�^g�(��H����&��B��q�wr��j�J8�Un_������u���J�Vpx�|{�K{�,�C-���8���c�6������h�	*��|8�������Y���e'��u\����.�����B�{�XG��9�z���l����w�].�Ps
t�b�7���em���"�`��`���?�N�P���0�Y�W)��5{��D9�DZ�����K@2���`
�=K��:�r��U&<�����n�~��v����D���GB�_��n��j	<^�P,�-�"���?�8����F���Z:�������b����	&��A��i�-�����D�$b��Bg��}��XWT5��*�P���r����MB,~S f����u|b���ws,U��@6���E��@���j����h
>�*���6&N��F��-;�Q������v5=�J5�����?��!�.;k�QZ%h����M,�yha�:7�2�D5�jSA�]�+�y��l��t�n�>��V�+D��q�$2������B��94��7>#���o
5�d5�]��}���:$�j���h�6���)y��y��#��(@�(�cb^m*�n�&M���J���8���R�������~�������m!�����)\�i�S��pF�����'W�D��q�!;6���c�B���e�yT��q�z���D�%���t0����7��%�����������#�$��e�!�*zIO��t\��	3���e��2��[�|1��A���yy`Nk����.��~�E�7�f����������0^�9���P��`�c	��K�<��t����(��)�(�
�<cN���R�����&��i�C��>U����`��!W-d���WSGn	l�� ����F>��P�0k*a��8-&��,��A�"�2�6o���	!�W�qS��H*l�V�	!�����������a��Q���mB����%v\1��H�V�M�=U��G�.e����up
X_+��WpN��<#c��Ec��T
bl0TFed	�aEI�	^����l���o�K�0]��b�]0������m<������VC
5YN�k����S��%8�������G�;.��k
�b�D�S�0^S=r	J�oz 6�a�c�
������g���&�Q)����} "eB�������z*{h�Q�$�W��ZO�M��~�b��<�0���R��k���n�%��tEX�u�R�\��x1WZW����������;�<l�)r��������=`R���d��k�w@�.cz�3�@F��kb����J}���,�<�����VxA�QMrf�8�z�K�qF8S�2�MM":ny2@X��Js!����pL�AD��2���"8AMt�\�0U�S�d��B�:���������Z�;4�j�B1����Y�>�z�K�
v�a%a��F}����Ty�m�6�7�:���m6�]
��E���� ,'i����|�-y0��&z38�6�PXS��.����S|�����h��� p���,���&�T��]'��51J���g������S�0��c<m��xRa6��^`���o!3�w4y���l�!9�����6Q����Eg;,���Ykr�a�����Es��{u���ZCy��@�%��27s"��q�&����%�r����0���K�����,E{��:$m$:Q���.;��6Ta�Mm���a(�6�^{�>rL��:#/e�B%]�vJ�4}����2Df��`B:�I�n�M{[��F�k	�N�4q��_�`<
PDq�����J`d�O@6�����"��L��(�cp��[34��b9�U����}z�G\p�xr�F�wmw�������N�b���L��b+��m>�*�F8�'��e����s��pd*:��Y������e�-ZV-,���x2�(NQ�Um�"��e?�U�jTd������L�;�w�. �����J���S�A�I2��P�m�Q��S����*J���?���z�!GY��Z��9yI`6'SZ��d������e,���32�e-"��p�8�cna��J�u]B�����L�&n�!,�|��"�5���Ai^��1yC�8[9:xt�j�\�r���7��������.�u�A;�!�$����3�	�[\F��DL��G���@�t��=
�5Y��v�+��&�6(|H��\Myz��=`����^���d0<~Bp"|?1�F�(����OU�7�j��!ou�aC��x����D�;
�#�6�njQ�@}^���W���K��K���o�=|�TF#��f~�(�#f�*Cms�x�c����^X���5�
j�j�YOz�Q"���"�YQ!��y�U���	���-�Bq���=!�I�z����<$"����OLw����<8���|�Eb�
t�����B�t�
n#��y���OPJ0tu��L����3���j���r47�����a����
rB�c���P�������fT9`h�c����Td���Z��	����(W650���1N�p
�J�e��Y��5��*��=��8ENf�"R���D1��;�>-$��Q���`���Hg�%��|�P������S;^�a���J�r��
�����G����E�<ZZ��!�t�(���b
���u1����Zt?��g�k��b�W��zh��g��L��8��{��)�/��2�L��;I2(]�t����9g���zz��������lF�y/l��;���w#A���o20�y2����Q.�nLm�����4��`�V�T������d��p��y����5�AR9�^5r��)�������*EB/!��&b�6�+�;�V����9"�0�����]��m0CA]�#L�W'@��� ��5����O�_�M�b�3�FU�NEY�GQa�(o���7P@��Y��kpj6�����9�l,����K`��T������=�^[�f	(O��(�t��Q�vub��py�2���>P�w1����	%��j���R/���GA�t�Ej�������x0<���Y"��(
����<�b�Ptu�h���^�{��m�+7>]��#����a3����#����������[zc��[��
����H4�h�����x��d=���(����CY��}hc��\��D��,��D:�u��U$���k�_�)��������4}'`W�����`��I�TF��n��sv��@�g1������V�d���<���N�h�y���F��*����e.����@�s9NH*/�4v'�LX�l����y�����P����9����"YJj
��?��=��\�9D����D�����1�����V�r�z�w{�;���Vff��#P�A	p�E�x#���7�e9��7,1^�	����
��z�R���kF�Nfo@���y�^�
����
\�x��c~:Z>v��P�~��m�`p�p�0
:���RkQ�oy���w���P^OS	{t�nS�V=(A�<�]id@�HC��0P]����Sxk�GV�WE�PHG	1���������N���V���x��k�,$�.���5Vz/��5�17��������vk�/��t����K�t^� ���U�����q�9�f"b��/u�Q\i"29��/�Gg!�: ��j8���[��1�'�t�� qQP(S�5u�j@�`��1�"_��zm���i7��������������j�(��.��;�_������a8��V-��a���^~�`����%�C l8>I|xv��Z1+������TW��]6���g��!���#&����(�s�p3��8:D���Q'M��{Y���,�^��C?�2��x(]�ef���"C���n���tK�Eig��a����$���.s*~��]���?���w�w����6g��x�����???�.�b�w��b����h���(E�@�a\F���}F%d��A��?�B��V�*��[G�������a[��u�}��*!�<HGe_�����q�P���m�$h�V��*c�,������1��0�md�]��Y�������]���k��:e�mY�8$)��/S;��d���n����w����O�Q��e���w[���y�},6�������<X;�G��.�v�)��(�YFf�\����	�`�Z���)��3���y_�'B���y�kGg�$��I�Y�A���b�Jiv]4���!X�g�4���	�Z�
���"E��!���/V���.!��R��b��oN����@����3+/�����+T���0�A����n��(��=� �������4w�.�*:�|a!�['<�y�n�/����S��������]��!� <�vU"���������5��I��ySm���h�������E��vBXD"zF?��iKT�����AB>��C���T��*wFC�L34�������;�N�W2N�������fh��Z$q�N���i
��[���!a`�
L2�%
��2I�>����X��*.�����+���\sx�����B=[3N.K���2n�]H'2m*7����$S'���,�	����
�����k�����P����&`�T��Ty��r��n�Bj�0������/s1�����Z���8����#�-�������Q5��Th��+)��P��&i��'�c�j�B_������Z+*A��/�����$�X&b<��w!`�N�����
��4%�z��U7�jW�]\�;�|��&�r�Pb����0�s��#pq ����e����&��Q�Sa�W��S��$T�	���z����a�J
o��n�����a_���
AW�0e=:Q���Uoc�o�������%��6'�z�g��\�[*�Y�7��q���}3�g�gx���,6��	
��c���*U�$M����R�C>����a\�RF���r=��(V��"|��s�&�� H�����s��B_F��#u]��=�2_��(���p����=�3r���R�@E`I vE������VA!��3E�Ne���C[x�� C������mju��K�&r������V���}t���g�:����Et3��J�{�:��F��VHP����,9��zZ�E�~�Ie�R'_�T���[1KEM=�H&�pqp�JYB.������~��P_���Q�a h�����\
:�'�C�n��-�������������g��y-��\�(����[�L��	��7	�z��T�	��M*B����S(����	��9:�_�����x��8��M�T��D4��\�
�Tj�Sk"y����v��0�K��AHd�k�S�.�!�:����^�e���M�������/��$d��P�����~_c�H�CB��`�}u�l�@C����[w���<LE��Y����k
}���"[��C;;C����m��P�p�*����7+9-��Au���U��3��2g:&�I�s�����f?8��B��Z�I�������#��X��oe�_����}{)�~������g�p���I�9}�[�k"k���Y�k!���J��(�6�X��gf�����Z��������s�>����VK������FE
{��ap7F�'�t�$���{C{�2"�6"Fq��0�b�?����!� Wq�F3���MJ�:^���y���0������k�6A����N�/�A�~��s�Ga�{E;�r�����z^�|{X nu D�@��J^�A/"�_��~lO����b�Vi��6�=��lt'|�o����:c�r������x������ %R&��HR�C�k�������|4
�,a�+��W���
< 3������tQ�S�����2|B$����t�����9'�{{�[&n
� ����^<u�������]�B��������|>�5��~W9�8��]���p������_�~m�"#�+K/���c������A�i��Zm� �|X�70�Q\&Y���(FR�]2������/Ia]�����h�
K�c��-��I�������V��%���tr����5���h�(*y���C��9u���5U�F}��|��,'�T}�r�(����\?T��w��P��_O�g[P�����U��
!���0v8^�n1� \���i�����H8���i����^��&0q~��=M��W��!�c�P��F�E��\�&`��}{���]6Y�0;?S}&Yi��H����G�cs����(C2�{��=������
���;��g�=�F�o9�bc����0<i�~-����n��G{X�����J�2Y���.?Ra.F��U���A�����q����yX����kE������,5v���O���C5��r�cy��v�*`w�
�	���
���n���4bgE����f$iv;T3,��3�����B����
`*m���je
#�=*
3�|�i��&B��3x1��DC]>���k���*6���m�.��L�����4VO�oFc�w�:�v����;N��?��J�7Gq��oz=H��I}�x��zkLB�x7~��LS0h�+8�vW�d����@��h��%���J}�o����M�����.Pe3����vM)�����Q`dS��feX�(;'���zV�k0��	�~�G�X�M�5��m��:��^}jR�]w�@9�s[!�D���Z�a�/�z��}�NM��}D4�(����N�yS��k2$l���?������?�)S`�W&����xl�T|U���@����^�9��w*/�������?����CN�6`�����K��+�z�g���H�1��q���� )>V������&����_-�}�-��G��6�3����Z������DS�y'b��X�@���V�8�@�^�x}�h����x8}{�m�w_w�.)���B@�~L
� �{������*d]��:��Z��)���R���:G=X�P+����E����<��e�M��6�l���~���u��+�]�I���(��)�������C�L�b#�{o��O�G K���g362��ZR��@��/����{����7�0�/��D�L�5�Rk���Lq���.�b{�X�Z���B��n�p.��V�Z���5;H"�KXg�P�dkcLVe�1�7hFz�V�����Yb?�����Z�wL_�F�:7������s�&R���x�u���9����kE��$��6��K��r�)}�� �����Q�%L���m�������f:S`�g������AR�=��	�����,����X�����l;��M�\_M����I��w��E��m���`�����{�v���L��)/_�W��M����
�����6��o�4������DD��!����0�x��p��O����`���^����?C=�g�U��q����_z����Em��|z���?�����yy��%����I����f��={W�y8��;��J�>a���-��>��CYn�xv����a�[k��������7���#F�w�� �g>�����Fn������l~��qo^��X[��p/)� �k_����"���
��������UrPT�����C����H�(�i���d�&{C04!b�yCx���yA��[X�o(��C��������������~M9T���tn]��l�,�4�_������R�p���o	����$S���5)8����7#��������TF�ti
�M�a#��4���k_H�Z�J2b#=���U�N�!���-^PlXH�(^3�$zb��s���������]v��f4"[n>T��3	��Q��y�Iyx�zVS�x�u�[���am9$	��k�9�}�uyMX\�8�����"���?
�Y��}E2�vR^�6����b�BBIz�-���
^
�����{�AZ&��K��p����>�IR�i��E	�&]�Oa�kU�������h����S�OEs]����9�����B{��.$�I�
����f�T"��E^���|���i�4�(�:�Qc�����������|����F��Z��&>�b[�bg����a�i��aZJ~�9uuYT���uvR?��Xf�m3L���O����<���J=VAv�cX�������w��@N����}JI��Q()<�Jf���CPzcJ]M�J�� c�
M#PJ�#(���a����tP�[x�+���f�@������-�:1
�hlT��|(+���i�Gr�O����d�#n��`��V���O�E��\��E�:����4[��$dkAZ��	0��-����U��d�I
��4.`�(fF-?����|�C����qQ6�\��q�Gw���Ycw�Am��x��=��l�:[��B�x��~�T�5���R�J�G����R�j������3*�O���1���%1%O��!����P��L�����0�|7x/��H���o��R�z���5���8V���(���X|�O�=KdF["j=��t���UEP~#��"���J`0����xY�+A��,�8z���#XY����&gE����4�'���%&���eOY��5L�F���ej5KY(N���Sj/�SL����QF����4��4pAz#�6������
;hpM�sI+�W�`�ju�g����RNf��H�lX��;�Y�
w��]Ht�[�K����f�]������^i�cH�-�]��v���s��%T�,{��0�nGy��j�Z�*�R����64�O��
~.J9�v���x
�/��Z)i���>QQ3U��N��BQt���?�YRa��ZPs/����Z�H�����Y���P�8?�o����LY�����FxkXyY��G�U��xT���Y����M&'e?��&���+����?���R,�V����`deZ��,����P���(_������D��T�����`�/
4������\8-{q�#�K�7/����o���xO`)�P��FCM�Ncd��K�o�KGs*�wB�k������q�?5�>3��/$����] ��)18\�o�s�M�q!Ib;����J C�m��R/��1j���Q(K����.�fe�zMH����z�a��	jX?62*@yir�i�lMW��m\4$��&R�Jx���e!v��:V��S����0��Z��������W��������-~b����:��I�-�\(	��QY��:��M����Y8�FF]];����=��s��X�:=S�-�Z�1!���K���@��D���������� ��P�{��@�-���������R%"��h(EQLo����Jy�>�h��y�7�����Q��r���=�!JT��s�O���2M�ua)6����)ei��e/|Q�`-�~F�t�+��e�A�uj���0���I��=���S����qO�&d�S���C����}�,�9U��m�Tj2�&=��W��z��\������c��!��t��TY
�M�8�����2$X�+���m�~^{��"��S�+���v��L��
t5��o8���A���A��3O�3I�o �VK-8Z���Dh_Ly�h���/;�>bGa��-lQws����~K���'�_��Z#�~��������gx��\,��p����Y]�Z*��[��q�zS\��0��|�Un�l�������v��/��}��}9A41�"���?u,��(
�u��5�/��S(SN#�;+E�IQ��3mo�� �5:���_����@��=l����WE�eK�[��*N�@��|��v�P�ZeR=�mYx��
V��e�������i\J����%�:%�1U��	!�@�rF
�����>e�GY������$����3d#�!5?�v-�Ay_1�#M|]�����#�3v������2b�jJ^Ky�%��]%������Z��o�R���`�I*�I�������u�2��8�bh5<(�-�`��:;)��C�w�d��~�%kdO�f����K]�~��C�A�M��+�]���'�Z/c�/��1�Hh�b�
���l��@U�gT�x���-��<���E�&���c�������Qw6`��J���K�����p���9���(O�U���W&���Z�7�g���B�t��#�\��QC�7]�J�#Rhl�;?�uR��Iv��[�z6$D+{P��+P��F�E"=McMK��1�|����e����P�Q;hZ�c['���g]���C:6����=$H��
@z��,J��f�DV�������'�_���pt�w�����E����3�'�2�����F��G�N������@��y��Mh�X4�h�����ba�^�t4�.��ow�|�Zp�!������jl7��(��t�|
���.0�"�I[y.FF���Z�0-�J��|V��K��P*��G�fRC�C��CM:�����2���%I *���n�����7���F���G}4����<�q����
��(sn�����#@��~�n�U}K��# [�r_��_Mu:}�^Zl[a���c��ge�H"�X/�O��ni�g*3�ufUol�rvS���a��S7�.���81�*�8�	���00f��Q��j}����.�������,a��+��^r���;��M�M�	��W�P/������@��"�]3b���F�a9j�Q@	AvXXK��
E�0�!U����X�No�y	�����6��Ei�4�>�9����������i���V��:?��1�w�]�:I��]�$��
S�2*c�a�>�����1c����2�PS,`Xg� !e��uI��4#����1�w9
�
�Kfsd�+���������G���9�����`F@9���d��un��m�+����La�t�U[�|����r��=�U�|8L<���������?k*hR���C�\_"�;�<Q�s["�xb�������.��i7�&��%�}��+�9�T,�~?9���.y ��
t�f{�s���&���y�Dx;�5�mP�Xe�tNV����U�GpL�)�W>��C�1��iy)FVhyI�M���&���y���A��I���U]�eT�|����tN��$FD������u���L�c����U��"�������R@��/kBP������70�71�G�$OI<Cx�,��)[���-7m�2�����f'����\l&C���]CGR�)�'�`�k^���n@�8l)�"�u�A��ZN�	#D�`��q�~��!B���8�������&q���0�����H9ob��ZI��Z��CC�8eu)xh��y"2���9(W2e�	��i�
,����bQ���B\�[RVd��>�_f��g4:����R�3=���;��]@A�;I
)1�"��i��6�3����u"
j<��f<.J�HYy�I�f��"���M}j2xG�@4�%CG��(@b�(�Q�R�9����������>s�v��������g�o���^C:�#�I�\E���r��^f����<���&�����R������.�a�M��~b��#��Gs����Y�vYV,98��u�]��7~�>�QQp�Osoh�j����WD�x����`��]��C�k�u��BwF+���zS21(�L%�H_�c%���Y6����3����
M ��u;z��N7������6v�S�N$Li���D�u��A$�_�0tpMh�G'%I�i�%z9G�|�B�{b��G�*�����QYl=1��������a���	+���}�W�k���=ys�
�kP��^���`. K�lV��:�1\V�e>^�����}�@��t��b6����,��'x�����/^G"dI��bf�F�{7s��<f�W�/Y���f��^N;�/d����N�
�<rI�xA3�����`��OS��IH}�:�y���Y�t]a�y���w�b_�:��`�k���{}V�3�Y	��:�UYxK��Y�����������w�����K����2F�[�vBI_KpU*��A�)^J�Q7(�B��Fg������~���.��x�[q����S�Z�v�	�����\�������xy���jB��y����%'�����	�@"��e���ra�v�pr���:�Z�U�W':�_6���������������po�J���D�#�e�$l��F��?����P�b�a�65�RM���}bR�;��T�$���
1?���(�V&"B���G���<[��1��A���k��Y#w�t�%�������,^��fn�pMA��������7-+O�����	���P���r	��Gs�9����z�FFt��tl�|���I��Bi���2�C�P4���3[ZY��;��� �N�a-R�����m�>�abl�$���8'��u�6n~b���
�g\����3����8���R6'���N��>�*�oN|F�k3S�q@�������(o�R}��m<�����-=*�h�4���W�HH1�������
!��������w���5J��Avn�����$�l��;�_�s���WD�����u�U��AI@�-���]��U�&+l��L�T(1�t��w�����}M�z���TD�}��g�;�8MR��,k��z�E���3��^�V�[`]��L�28L��c��6u�@�^PYT�&y�s�g������y�[��j�g�����)��6����\� ��8:pd�8��2'��c�I�6�����~�z&���aSf(��_������^�}.U�������G��K��p�)	��3������M
�K��Tz��i)��\`�'��(�%��#&��]�d$�dC����xAY	=���,��YO��Z(I��XZ �?�GU�I�t��C4i��l�	���tm��`Z[�yC���������aU�(����*��~����*��p�Jz��b1Q�}0��������{�*$	�y��"+1cH�*�C�=�z��"����R(m��H�uV���ct���?�����P�{@u��Q��i�
�-e;����x��t������T*��P7.�5n'A��@Cl.��)���&I��4�L�Me���ANj��&F����JYm���3
�B���l�B.x��sv�<:�tM��RLh���xi�9&��>|��������b�K�"M*/�'���a~?c��mI�iHz��^�G�s���.�J�w��le��pX�
Sbf;+�$[�����5�r���
�\g����������y}�NX�PX����<qIhiP�����)���u�����z��HlG������e���)�$[	�Q���X��Hs�zR
�
i�N�V��s������.��|
%��
#[��~FGFA���u�S��/��c�_Q��&���b����F�\C�{��c��7��"�����u�<�o�ty��<
���$'Glh��F �iS�����N]�--�%{'���{��hg���<E�����[xc�K��������
�l���8$�
)��M��,p�V���0�@g����Ly0O{���[~5������py�1���w����8��z����7�s
L(04�������Hw�,)�
��Hi"b��
o=o����F��^�kol���&�������"�5��6s�u�c\
�&+A|�y�{n�V���R�	�Bv�8N���S�^G�:�Xn��N� ������ff ��B��j$�."��U�R���c]��W{9����������2�
�POG��9�@W�!R���xoo�pwP|5�d����I3�����{������[�:����8D������'�0���s]��4����T�-8��vS�c�#�R���,3[]�7��@���c	� l�<�=��(���>z���%�hg��Y(BAx�A=M[fI���sj���B&��P�@�p�����]<+a�
g�aq�����{!��;��������:Z6���:����H�$�2��S��zL/�`��#�"�g�p�-�\�U
��F�$�����]Y��h����	Q,��
�U:�����~?�"�~��
�7�H�M�W�*���C������61�J�i�	��-�+.��
� 8��~�����
Q���u���9dk����s8~�������=M��%����B��]�^,q��������P���E�N6��S������+�����PH����T�M�y��K{�2��Hy�K���#r�� !�K�`�o��������v����v�?� �<)W�D�:=��a���`�M���%J�]�D�A��Y#&�Y�|a�b�q��_�l��^�E!4S�%�%Y���i. N d8�����KdY���A�<6�x_�%�B����s5mj}a����]�:&D��\~�g�@�pz�N���;�g�-�*�Z<��.CG��)�ty�����,,�����Vg*K���r��s�T|�+wbG0_g�zP^�Gp��#�g"g����l!���I������!�U�O.�D2���(g�����������@���*���a�Q�������|������@��g��x���vzf6��*�rW��aq!_����[a��l���q��;/Y��g��,S��Q�����������b�����)���j��Tq�V:WEbh�'�@ �������������`NB���&��'�A�B��-:����m��_���m����o�u�����x������yZ�5�=�_�R�'�^��OA �����Rd���F=���:fR�m&!Z��KmgZ-�M%�o�O}��E��gR���<�2�� o�������s�,�R�3����%���Q��VD����P�z�3dA
�i O.W�Us���HV4�"�YW[�u��A�k������;�#{��2�QD��j�2��`i~��_�LnF���>o��8��n=��g�0-��_)�N��A�.Q���F��	��/��}�� sI��w`�D0���B��K<�����M�@
TqB��3�~�?����B)6M�����]j����d���+�=h�~�;�?#�
B���.{�+�nf�~�2��U2�D� lT8��lev�jR=�����o�-Y
��n�"h�7�n^��~<�%��S�8�Kh��Q9��1c����$,��F�,U���z9����4gq���^�*^�<����H�N��D��<OKXK��n�dp�9����S�!o��(!��
ZY�rL;�)@"�_�)<
�j�/�i�a�|]N�$��0^��� ��=��k��.��9.�;����w�{P@��A��z7��ae������Q�Q��R����x�F"(�?AC@���N'#L# ��N���S�s�E�����L�J^����!�����A��d��B�pY��'���_��xZ�{�q5���8���#t5�W�����������6br����D��3�t>��D����R`�o�m#���md����X!<���?�������]u�����S�w.
?Q�<WI�%��]�������y��{���0����x9��Vy�
JI�";i�k����UAX_3�
QSe���O�glc4j�~"d��V��*���fr8V�G����-.B@��
�f�m���}�m�=%Q4�\AI�G�cj
�C��]�=�P�!������O�%�-U�-����L��[�S���q��~4�zv�u�{�^���&]=4|M���`F��ifE~������[4�I�
�� ��o�5
���i�Jit�i�,<��X��*������@��EH���x����u��m.|����P�b.l�L�Y�����N�$A��#��y��Y������k��p��Z��-:���k�[��7��/�0G���Q���l����p��:A4���.
����=��@R�d$�)�:C�n���% �r����/��+��}'�),"U��"����_������$�,��P��8{�Z���4bQ���sX���M�`/�����V�j���D���e2f��Z��A�ea�����W|��7�����{*l��GA���(uP���U��4c}�g�������x3<���5Y�R`!l�|D"oy��*��
F��v�=9��W�����1Pan�?����_/P�X��&�;u+)]���*l�<"�ly�v���m	�neV�
����O�{��!=a�_��,�f.�.��<OO������{2�{�<�����+3�����t�p�+������d���kc5��5����{�������f����������K�Gq��}�E�k#+���u
��G��@���n%��0�I�@-�`�h�z�����.�/�<	����V�,��[���K�6�����k�dE*��U�*����1-A��!yk^�I��3i���}g(���Y��1������-uK���Nx�g�}�5�UL[�����P����he������p3cQ�����Xs��"���-l-;_3�-c?�c���}C�nZA�M�{��T��	���V?3����<�E�/�����K�������(�^L��6�F�����6e���A��8��lv-2VR�e�H{��
�vl#b����Lj��i�-��*�	��.������SV�:o�5���@�_���r���zn������2v���if�=[�[Or�/��o{N��U]7@h���m�>���y<��D��G`�k`wu9������%y��Mt	&��i�_�q����W�B$C4�'zw��8�p����FvH��h/�[��2��q��v�<�����e}��k�����1a,���'�O��|+LNM3����[�p�����������w��\)��\,�;5�0�#�>��R�O0a����<m��*�w�<Kz?���xS������%���^����?R�-&�{fc}�Lm��~�OY��Q������V�,��n���=��%"��-s�DK��_���������k�}�/�k��=���6Y��;TPu�$>��yln�F	c���
��% ��L����YP�mL����a�Y�-�1�c��j4v@����0����|�J�+�(��d��2d���S�L7��	��m}F���s�4#Y�=�'��e_}�)'��L��z��~��&*��~�@z��m�����:�aU�Y>L��>�r��G����'�Y���A���v)���lp�|��^:7�J�����_��!W��!/�F��7����5�6�1N�^�!����G�`}�9�zZ�b���8���
�y���#���fkUmcf?�HxC��GC�Ack�b�FV	U}����z��|+)4������R��Y�[@�N����r��`�~�^����?���2�H��h����{:�"n�W��s��\7���BU.i�m��uY�b���`�,=[����2_+6�&��.1����@��^��e>A�����e��h|�!*��~��*�������9��`N�����
�kb�r�6��?Y?/� -�����.�M���O+�6�Ne�8m��Q��gj-���h�o����G]����}�q���E�����(g�n�>����1�`�LSna��x:NP�\�����:���.9����@)��]<�*C`�7b��"5���,�5�����O9��^D��>�iH�?���~��{H����10����4�YUo��cu��=4gS�s�T�����y
����9��)8z��q������K����#��gU8�=a���v�a	f��������.�gf�<�Y��9��}g'������1G;C37����Xe��5�C�y����A�������y��L@���q$������{�To{0�c�*�
�����U����C����2��?qY^�q_�_�7�w�H7��F���T91q��Cd��!��������;�����k��,
<��Q������od�a	�����<�<3���%�4
����&sP����b��9����C�xj����?��<(F���=l�0��9��~z��MT:�%a�I����&�A�AU����<�#�6�����XsCF�m!��Pp�L�������p��D�@� POj{�C)���O��nK�<����f1j�`�g�\&����H�	�!�+E ���U��`��y��o��V!@7;��9�����	my������=*�T�!�H���]��
�j��`�s�v�%O�bGyq�K�����\JO~f�I[�sFV�&���8�����`�=��|l�IuL���1[S�ca&X�������V/U6Y6l���?���������	G0���M�{�=LO��4w1�::�!��=��7mf�~	�1��
r�r�y�hK�X}�����E���bY�foFR�2�$�^��������un<��%�~Z;�m�~rXwj�������<�����45��Nh.��{���5��w+�x���7��'Z�t�R������
��5�E���R�UM���$��vB=��4{^�t�R��upyN<Jz0O%�Bc�l<�W�Jf�fb��t�������t����!�l��Q<K������&lhoN�)Q
����M��{�Y�{zY���7���m�$��ku���9���*�e�O������ �)Eh�N�<���io��+�~����4�d�Z��xdx�_�}y[X�*�4��X�����{{��B����X9����T�5��yk�D��3��*.�_;<��,@K�]om�a��N!������{��vpG(?���j�`c�BcCr����dHIg�d��� �6��dLf�;�31�ET'�L��n�	��Qi����PB#8���<�u�M!3s�B���ver�hw-p�/g>f���z�����m�/���4P����N>X-43g��&	��8W	 X�O�S,��Y����4���s;�)]���c���`�&��4Va���of�BW���L�������mCN�WLc��0��J�b�V���tp��\b0?����o��tz��iS-l�	�5M��������n�h����������F��5b�����g���7��
����-���^{��������~jMG�u��]If���/��(�%O��Q�Y)�������B�������G�����O�a�^�Xp�
)���uU��bd�����*'�7����P��M��<Ml#�50��r��,yx��M�Qp[�"#��0��H�m���O���"
�m)�����9����U�,]�Du����ge�K��*F
��5s/^K�&z(��+�6����a�JW��!������/�O����X@1
&Z��$3&n%[z�/q7{���C�6�;�S�t�[d�����J	^��v���=@c^��L���B�����g+cm��E���c��C�����MF�kS�h5�q�����y�*�acd<#*���~��m�J'��k��5u�L��i��mgm��JR��e���f�>�:��i�����,o�?���R�3��I^i�~�9��wm�4+�S,�D2m�b_��:��R�4��4q�Bb�gx�0}xL���B�	F|�Py3�!�i�q�6V�����m[.3'���3�"�p!�<�+?f{�	��}~�����������s�'�t�����P�	�b1���n�#L�"��t^��2�M��y���@v�u����e����E5�T��7_;pk@7qF�Ka|_"������JT3�C����D��Jm�U�xO�7�x��S�}TtR���w�j7:�A�W�G6�f6�N"���RHL�H����Gez�WfR����TA%.Fz���b��P���9C�L��lN����1B��jW;����lm:]���6��A�&��@�e����N�j�O�g]���c�"�R�~�����prx��� e���!2S2��@a���
*�-�U]��}���#�s���Dq�~(��q����p������"�ifr������p��j�(�a���0�kT67�*�bZ
���I1p>��o�Be�lBL+��:�f�����vB@�����{��������U��o{01o��%V7���9��@�kd
_����$���e����������k��
*�bjQA����c��=��"`�b0rKC�D� u�eA�;�k�Is�-��8�m"�y��+�4��k]�^�j_�`Y@��s���\�,��?
<�%����t�a�\`�1�v���)q�E��]�8St�|�j��K�PI1����N~C������5�Y�b*OM�l���X�W�r���]=sf+�(6��s���������t�<��(L��/Oq�:~��^�*�8���3�������6>���]�����?Cz�g������?��=��.<����������_]]�\�������!� ����2��b�%��a�R�O��U�`��)���3���s����_-�
������L�y���KB�wP^�<���p�,������_�����On@����5�^2����P_�}%��~���&���� 2�Om����J���}���~�+"��-<�~o�0���-?����\����g�����Kh���PX��C����� \|~��x��Y��}�������i����g��{V�:���:�����%���I�]v�_�����vzaQ�p�����g���U������Gm��*��/U���:i�������4������7���^�x�����+���������o�^<��}����z���������j�W\���T=J>��������~��_��������k	RU�����s�=��7����������N������/�_��,��3S��(��W�A�g�����:v>���@[��k�B��j4�J8~�������[E����&�����^A�b��kpaEp��{yK�#���D��V�^L���e����.Y�&g���F��V(������3���$Eu� ��cY�L+*u<��%R)D,�R����A6'�FV�R|(�_z@_+������o�{�B��*�y���J���?�a��������,Op�,�#��F�
d��.�#�����Y�'�i��O�Ll�	��x���V�	x)?�����[	�8mc��h�W�V��0��JK�����^xD���`�x[���#�����M��h������������d��<����T�#���:������Y��\@�|�7�o��F�qSN`W��<�O�Z:�,�q��}����g0>x4K;���k�se������y~��ys�����?
��p���or0x���M�W����/�K�js���%��L���������_������:��|����� �������5�q+$P����no��i��\��������q��_��5g���t>H3�np}��=�NUX_��;f���p���C�u���}��oo�����[��	�=�����������>7���/V[����:�c}���;*[���g������o����K��C��
������5�cc��.n�q���oH�,}��v�b�����`Y[�S�[�+_�&i?!�7W�G����w������@�|
:���������4���3����^��i�t����R+|xR�!T��Pgc�%~mu^�9��q��$�#�0���Z��&���B�s��R����/��/�(g��<��q6���V��Z��?�T�/]�����[~�S���Q�E��6g]wU+�z�a���}<��cS����o�La�-yh�H]U�3ac��z���� �����u3�PG��m9$��
x��q��9��F��H1�5�f�����'���$���x���_��d�#�u#�B�E��?���Z��m|7����q$'��n����c�g�fC�:�I�	�uu���)��c.yByZ���p�>�q���
�]��<��CT<�B��3������$^18}��H3�������Z�&yY���\Y]�_I]����d�t^��zFjb����YS��VYk�<I�z���b�t���KV��~���q�y/��c�;*\1�����],�Jb�'�}����E�g��K�<�����^��������<{u��5=�)�8�!D@��	
.�#}��_�y�������2�fl�@��(�T1�(c<T�(Y%m�
q����W�F@�e����/��0j/E���a2���	
L��n-��A�Pb��*�4���y�|r��'�z���C.X[�r����=��@���7��r"#+�����N�W���&��lV[��@�C>>:�r�(N5A���v�����X�K!���0}T�95N�G���hs��Z--4O�x���dHa5�����P2��1��K����u�����O��|�M�G��p���f��3A�;����K18�/X����3�@@�H���^gX
��O6Ti��Y_0���,��a����������7����Y��������V-[�E�V���^�X�jP�;�Z]:M������><IV/yJ"�vP�hY�C��}�TL������0�w(����{����A���� ff|�)#���X���>o�Q�9��n�52�,���/;�N���~��D1��sZ�)���	a�����X����U��u<�z`9
"8��0�����R�<�##�����'�G���\1�����������m�Wn^tl�V����I�\���:������]C���s�t��KRei�|��-.{�@���c[��rC�?�G,Ly��U��h�����E��r�i�/h�3^��
���G�<�Uj�:�*��BU��0��Z�+n8����~����w���z4�������	`N��,���r��P��w52����yF7c��m�h�������C1���`>x���?�7�Z�����(0���p���3(3�������b��+���I� ����iu���x� �R�>���B�xL��:�k��
��jG������\-(X���1��B#�rH��s��e�!���i����G-zTHf�r�!�cBeT.b9��-�V{@��j@�L��b��hw�!�R7Q�8��������;��$����
��'T�p������P�S=�$� �p�~��,���%�W���c<���wm8��< �S�;*�%�;����A|��q��a~�������e%Z��h�9�w.)]!_L��o��T�)��b��a�8���}�@$�9���
Q�{��*-+�T�
pNmYq�T�o9'�dA���$oU��m�s��U��d�����*q�Z���� -�{�z��s���9�q��������oUe:���n�o�����1�N�p�o�~I��g�~u����l15�yi�#��2�q�V�d���M����#�N�*�Mh�wl�
3F������x��n��Y�9N(�#p	1�Yx���]�0������q�"�����qx������GE��z�a��a�3`����Yl�Fb1����*h�#���(gct>��c-�/�����AP���P6�ac�.�/������������8�"f��AQ��i�����{	O����7N���8��f��������"{�an*m*��O�����0G-��t�Ec���Q�6�*M�R���;��N���"��j����+nM�w����I�=���_CB>�?C����������}�a��3��R?�(H��C
P��8qFgiG�7uD��Qa���zd��U2f*���-�0)�9�H1\�S���!�)/&1'��]�������`�JE����
�_v�p#��u	�Rp��+�)jA��pR�r�b�5�(~WwPV�0O�"}��M>ga!���*�S+�[������<���������=7��Gu�L�z��fEx�h�\Jx��I5.�1L !����8P��4F�� To&�d#}g�y6Yj���d/�~8V���6�����ZEr�
,T�$c�(�Da�	�F��XD5:Xg�*i�X�wz}��V�3��"�
k���O���kaL�]�r1�4I*������4�W/>X2�uU������_]sa�:����L�U��46��%�j�8�a-�t�AH�^��D�[N����>(�0��P/:	\��q}��R��e����5��hg�cu���C�V����I�S`J�^���	�T_>��%��K���^��P�0��\�����4��kx�-�e��-��Zi�������Q�(��0}*��6��u<M��5�3�gs��-=�{6[�EO!�S��n9vUh�Ze6�!��.��;^�\?u�������4����m3��G��������C��K��.�C�?�vK���p.�kShL���uf<�����8��Tz4rlH8#�X��Y�QX�Y�#���X������R���=y�����
G�y�p]�z����23MZV�(��������!�"=�|�w���/�{Y~I"�)CRb�b��%	�������o�*�[���4sF=�v��>	�B��a����o�R� ���F�hw!��cP<��-��"(?0�l���w����;�m���B`����R�+���E0[j�<�RqS'�YV�]���3&b�Moq�KMQA3�k���T�EE�I�?����iNe4Twgy�,G��j��_�����J�5�`�8:�e���]U�^=���9��������>p~�I�]��R	������M��N�$��=�d���&�2�������NC���s��Nc�	��R�_lr��@#1��v�f�K������6C�z�3qX��,*���K��X��H��$/w��i�x8�a���&����$�$P��s�1V�B�]w�]�H��!��Z�T���&����uh��b,�u���T���K�8Yd�	�kPy@/�����ur0,'Oat(�$���hT��^��g��*>B8� y�]����h��1e���x�Fe����q���������� ��j8���x/�Y�I�gCm��@7%��RLhE
G|Y�k4zZ�m��|,"�hRAH��*)w,���4&2����m��S�������3�(K�(N��@O:��{�
�J�������C����3��z�r�������=������4��
�����.F�I�Z��J����)��~M���u����2�A��_������LOtPQ��iI���}c5^#zK�1FjJ�$�$��3��(����Q��N��UP�A\vP����y����W7���z@���|�1i�:�4�,k��M��Ou���� 1���eNL+����Pp
	Gf�S��
#�x=��}������X'_���������q-�l�2O@@��~��?8�3M�^8�����1��>���.������x^����[��6��
J��m�
���_����<umk��3v��.|OY-b�0�P�
8����"��d��[c-��N��[��)a�Qt6v�	-)������L������h��'��.N��J>���(���#Q7�.mE�w.�����h��!������8��N[��IX*�d>���d��3������N!3��R�N�.�R������J�:;�B��$���A�c�6���"�zTw���l�a��a[��M�Y�|�t�}Q>s�
�v��7�WW��u(yB���������nJ�=L�]-��ZT3F}N��C���lU����YA�K���?���Z���t�L��vf@��i��n����s�C����v�l��U�����@��������K���h�`�Z� dR����
��C(��x�"����1�������(�9i?���
��$�weW�]+W�1SY_���D^����gF�3��\P�	�"��Z����5:�
�XyF"�d0	����>��{!=M���E��3���
(�i��xY���_�Rj���8��Zo����V��c*�Cjf@;����Y1���LT������Rt����F����Q6X�M�U�c$P�X(�����Qw
�������	;�z���:��(le
=�}��6KCa�p��5VHZ�=t�P���R�O�����#�+��l��&����.U��!��s{��9/k
�\��]|������X��
ce&N�	Es.��F�� S�3�n�"�{��z�)dk0X��S��G���x��vR^#o�8�����h�!'��lF���C�cb����q��f)�LJ�:��,}�0� �
��@p���I
m���na��O$OCh|;�V�o5lA��)"���>����=� a�6�a�S�B�����2��{��{�(A�.]F�2/�I���0�K#d).eehB����-�H`4������4`����5��M� �0l���&���O��~VY�_����3��GaNg{C���c?�����AR�E	-B|Dw��u�OH�9����?��D��`VQ��7�� ���<Ec��Mb���;ag�}�&�U?���8b6��d8�!����D��;8�p�q������2��,�����E�
��d�F8.�t��T�yw�\�?��k��PtE��6��bM����a��1:�������V���K�m�����gg&q8�]�����z�T�9�6��m���[����n8��O��e����N�����U=������
�z/���o(�P �����x����Jh��I�%���/<gs�p���"c$	V~��;��!��9��R�q�+����P��$�5P���R�&����y���lF�?j�k��6�7�� ����<���D�B�Z�e-�e�f�C�r�Y.�0;V�S���m�z���r����ACw�"�g��"P�T��m<�G��4��0��]�������,4�c�2)�����jf�B���o_F6���C�P	��q
���Aa����`s�aV��1��D�H��
J|o�.hL�7&AdtP�r��J|���CZ���Q��N+^0�k�����M�k2#��[(���Z��n����
U�SdJ�sr��0\:I	�,��)�Z������j>B�~!�%�������0(��J���B������������e�������
Y������;8LE��������[�vztP3����48�W���S��P���T}�@�4�I���C�"��[a�mTX������?���,����D����)���l����������+�X��kg*/C�YV�d ����:=E��R��edu�CqbQ�����������������z���)@6u�*7H���-
�c0!�5&�O�Z��3P�����-2q�5+siSt2!�W�:�������G X]����%��eey/����������#�������� 8�������,s��H6���J����#�1v��e]�q�@�\�gfg���R�'����Ju������PUo@�wx.[?�g�g�a�HDc����TU����@ C���f�U8&���0���sl�af�?����fP�:gg��Gu�j�q�!��WAW���C2�c�~i�h�����JY�j�:[�rY����O�Q��,~8�����|LcY��&q�	����R��CX� ���`���N��#T��p�m��zs!�ZD�*�4:�������s8�wp@a���{q�����]�����}Sx��m�0\�1Kq�X��v�5LL�-��M�o�_n�>�C�Z�u.�vd�7��5l���a�s����r(T����{����S��F���,��Z���P0��U%jjH���;��ID�����&������)cs-n���9e�/���Z���4
�\0���`k��Qqo]��MYTa
�b]qp�\u���#���37/��h0���2J+.����:	N��yL�����8�G�v��-��0FU
���� ��>�=@U*�B];�"��>$�sp�K��
��V 
CT_�e�5
�&�C`tQ�.���S��n�����X�u�#>��^�wZ��=)@�M���@b��~�(����c�hj�.����S��*E���|@dM�I���	*YW������t{�mB�����;�E�!���PBU>~�A����0
����LS�������x�H�������.���=2P���A���^4��V��<�D�7��%�V0�VR_��?R!�^{�6���V������_���,�r�(��u������a�4�7=u��jw��	���6S��Yo��M]2y��^P�o��Z ���
 viN��Q���C]v���I}��� �=+�!\Nv�`�	���~��f�-�PUO:(��s����/C��\�
��fUT�V��7�Y�x����x�����S����4:.���a�}�B��Q���&�?�b�����*�Y���#����^-YW�N��,�P4��g{�
��\���������������i���T�����V1*����
t�K�*��ZT�+��=v��|�V�-c{��6s6�L���jqc��.#��
2
4�,���n���&:�����E<�ew�u):oaW��*R�G����"�����-[��`1����
�-%��r\u�i������Ri�Wr�6E�I[T�P��]B�����E�X����[|����-���MQ$�S'q�;igP�����+��\���K���T����S�����=����~��+(�"���u��]F�^���#R�&w�]��#2�����]Z��4J�nP�/ZW�c��U��[��4����z?����N�)$�t�W}!y�T�!���qt�~�>�\!��C:�B*)�!���q8���v,r�@.,�9����w�fsn����Q��N�Q��5!�b?l.�����I�Um�CR��"��RQ�}��)�)-
X�:��${y.��Z���3��0
������I��5JF�5�pO;���9��5@�8�~���D���p^]�+ ��~���X?L��j���^9?)��WG�����6�^dk,����C)�����VR����r+�oyY��$J��oD������`�l��fGj~���Jg�d�
��RYY����]'u��A���Y����4�;���
���p���f��X4��k�|�����`6(D#��]�f��_="�s�;�8�&��71�_J�L�%�7\XR�j_h�$��)! �;_	����j�*����r�ZVK��&�o������Ct��G�f�p$�X���H|��!s���?�(�JP.�:H�w��<�Ns5@��y2���}����Z�s�!vA(xn�"�D>�u�;���.�k(�]XC�$���8}2c^�G�*�'���c�e��?t{���6�wB���El�3���
��=9�_�BZa&6�T�:��bv��N��) �F���C����L�%U���������%��Tww�7�O�bMuB�+��i7M�x�d�7���-������O����(�)���!�Do��������xJ1$��+�"��E���z�^�UC(��e����y��zu�.�A�z��FA�`��D�bs(�c�w��zX��(�{;��8%����O�*
�834�����R^B)�W�S1������Zf���m&B�4���D�������>����i���,��:4�|�����#?L��7���F���=h��
E[�<f�Z,�a�M>!-��G�I�w��d���dG��L0�}�ZJ�g�����!g������6e�	iG�`�XE.`	�Z���%�.-������&:x9?�"����x�c��������p���+����W��f������Q�o���A��j$di����B��s (����b�;Q���L�nw��������pn�t�d���<�^SE6I�A��
m*���h���enWOW�?�7��/�n��5�P�f�I�F�6�T��h��p����Q��T�(;��.��]�	��P+B"
�Ns����MuAAd���T(�m� ��k��z4��_�������5���O�+�<����M�D<;ekRgL��6|H�!�)�Q�|2�AM�'�
�Jq���BY��H��e����:2��Lj�M�S���'s�C��t6��I����n<w#�Fa��8P�s�D�>��\��?�����{aR�KO�Q`t�7$(�,w�#���l�r�A��a�E�b���)�� }Qj��A	�����$���V]�j8M*��MHE�[ �0�W��:'&q���!����C��?�\E�Z���"��%ro��X�M���[�7�q>�="����:W��"�|M�*�?o!
�0-��Y�D������.��H�,��������)P��m?;��D��w��}�C]��[H^�����3mc
��c���(P8�8w1Z�M��$�JQ<QI)�TBe/hpL�B���>D�����J��W�(�'��o ������-�Mwy~���I{�/u��:�.�t'l��Be�.����K8����_�������h����kO
i�Un��d�E���U%2�+�1��_(�E��		���"d��[�0�5r$'�)�F+"j�4t?n��(
�{�VH�P!��>H��@�x@^�D:i�����m���)7 ��12�si+	�!��Yh�����d\����)&��Ws��M&0�� ����
g5g��3uT��"�p-^�v���x|�����Q��Lb��$�T�\3���V�:h�
���L�x�w�R��3P^�����C,�gqI8�%9$�t.u��zp}4/��G�vc�6���I�Lm	��:�IF@op@G����R��1������sZ`�RWC������u��������B����)&E��&9W����9��jN�G����B�i����F�����<*�I��<�����T�D���X>��;w��X.#O�E������F��Zb�b<���\t����H��`��3�s�eRcv]'mW�=�3���&���g\��K�q ]/�0���C��Q��C��+���E��Y��W����;���=<��Fb�����oi
�G~ ����B��a�G�
���q��f~Q�1#��e��\xv��K��P�g]F �:���j��OUR���Sz�d���N`�`$��	x56lNH{4��_ILkFTS���3~sV�a��;�P?����|���X V�F�Xd��@���Je��p��q1{~N�`E����f4�P���12Oy���SV��9��Q�h��1�OQ�4!�>U+G�8����"K���b�J�l���� �
�hc[��X��f�� ���)b��+t�>�}cj�t���
|���b����@��,��EN�V��HfC��,����]BZ����GuD&��H'`&Y�RV��<5.JH�F=�����3g��w� ����x�uD=4`��j���&}�{tV*��ku���`pBM��x��8m�f��D+�+�i9V�dE��l�ApxS
9��A�}�R���;�����~�DSMn���������
�D�!�Q;�S�����`�������t������b��03>.���.���)QE��!�@�����Zn+���N���R��.3�I!� /��)G����F8O6���Q<���A��Z��2�}'yH
!}QW'+������};�5g-`��K':�
d!����(�� �&(��A��|��U���i:YXc�|���N?��� �����13�^]Ag��IF2k���:��K/3qS�������w�}*K1��kE*��2��1,U�o��E�[	�F�hf�m�YN=�#���������������!yz'n�/2�������9�T:�C�5���1��(����H�X���H�N2b�(=�:��	�$��I%�"K_�_��i���r	p�0W��Z�}��+�P�����i����o��m����E����c(%N%������T���fd�&�|iQ\��j��� ��1s8c���M�L-Wv�j��	?)��4������/�0b%�#.�YG4y(�6��0��e�j�	YY�`zQ�����5t>!j8S-�������#���g���G���(�����}�AiGW����
�Z����\UMz�!M�{���4��29!��00z��QV����F�pf�I�;=<	�7�����RW�f��W�!�G�L� ur��V�,f~d
���$��r,����8��d<7n�ctv�p-����0B�g
M��Jt�h�Pd�i���e-��W�����{:���W�"fSG��6��m�?��(0=+�Q���^����Hn%
���
.!gy�h�+M����d�i��Ba���)�hjF]�s�����c3};u���J����$�PL�Hf3W����WM�<~)-���}�e��|X,�6�>��&�m�k���(*��2c1�ag�2����i��E%U�=!�d�K�A�z�Pl�����<>�X]w��,Q�%hq�1#q*���KPA���\D���x�Y�_����q8B@
�8����?��<��jyU�bD��PZ��S�!�����Z��N��B�T�(�\�������I�1�j,��|�[�g�&C��Q��0e"p��P��~+t_��0�6���T��2�M?������j����t�8��s�W�@��k������xg
�i��B�Ju��|X���	�i��C�v���$���d��`�����SHo#��XTW����*�|_De<$����/�n'|���K�G�vL��lw��\8A�;]��mW
�l}S�����z��<r*��#�5��Z��`��:�2�c�S�cY�'�Kw{��������m�Fmd�f���m�$�'���'�\���v.��y�D�>e�.u>lQyC�kh������"���d���e���Ut�5�53Q��))��H�>w����$ �������$]��<v]rY3L3��g������Tq�y���X�g;���485my�f�FH�����;mgs��'���&�i��%.+�)���v�!\}�A������X��7�P�`o<��>����2��B�^y�`q Tv<V<P%���zhHV��������z���	����Q� yrX���Y7y����ZV��6�z�q��85��C!q!�j
jA���I6����
v�������x7�OG���B�\E�>��:����<���}*2���,����V�cU
����T	��-M� �������sN��6I�!~[�wK�r+f*���V<d�V@��"R���!.��@���y���bi5*�����!]r@�%K��k�v����k�����b4g.���a� ^���N��us�V��3�T�����������le�'���3��)���:�Q5�y0���OH��gG���d�����@��
j��	�v,�'�������S)J��i� ����U]�K��N��Z�wn���fi(����HRx�v������%+���h��e�iF+c��7��&@�D��.��5m���%��;T�� �S�Ds�����1b���Mk���y~*Q��'��1���dk�_���k9�;�z����(,>�������M��TKsb��8���8��{��Yz8���B*
��4��]f���C[���#Me$�R���<��uPcWO���g+�$���<IV��7,������/��k�*G*�V-F�����c^?�WGY8���$m�X��@�K�E�z0H���_D/6������zs�jg��n1�X4�^|�k\�Y:�6�1����m
leA��O9	�,�~���x.?@.�Y��i�6Q���7��o�'�u��M���N��Pi#�!mRt���j�JG�:ky���P��1�HG�>4��F��W!'�a�;W"��8%�������D8:!QL}�d��P����<��-���2�0��1s���Q EWMt�d���z	c�$;����v6=�����,�@\#D���C�e��nL�xP�8�I/����l��hSQ��02I�T4��=����.*�bm�XJ�������9�a��#g������sF�Xr�F�g����1�o%
���|U��c�$uFL_?����{�~?9U����ZPa@��Q���7V�,��~�e�W���Ld����&z���I�P������AR�B�Y��i��b�M�A��>��\5������(������Av���9�2=��T��������q���P�
%�e�Cs���PWA�bYZZ�Q�a��nO�c0��cE�uY�p�D�v6��)��@l(�I?�����9�E���U�"i���V��W<&]��2�������
�3�g?-���C.����e��;?�@%�7�{@^�u�B�N����;�uH�Y�3���<"#SYKm�)^[^$����F�P�"}�s���s�n�@�@��
G����Y��q�2�����dR�#�K0���a�
O0V#���UL�-�}���1{�{��@/��P�GH����K�x�|Uy��w�(���2�oq�o����d����T�:����D��@����`��������@vY�J����7!A����C���>��2��v;@X�\@��������@���I�1M���U�$�Ca���T[M��g:>���=T z�����b�!����|���V����_-${���b
����k0����B�U
���&��V�N���Q���(PQ�}�r���a�;.��4����h����Z����h4}O*ps����2���0#�&0�;b�$��23�&E6|u#c��.���p�Q�f�0$b#�{V~��������T�B�P���'���J�-��tg
�� �m!��uY�
*�de��h���/~�d"�X
mJY��"���8�Y�/�93%��U##�8(��N��Y;�MT���)�ZHbq��M�w�4��D�F��k����`0����G��{���fi/�Tkj�v`z
����J�{�X�879���_N�w�"�/�#�QD��7�!��G<P�0��##��a*r��������=B�r:w����y4�������S1����>��C��u���!�1�z>P^X]�l��T>]�g�
{��)�������]k�:���Ld�u�����H��}�U(����d�=1��W;������:8j�w90�j��PUD?�l*u`���\4��6��?������
�Q���!���
'V�����+���{�f��d2C�36�R���y.������!�:���;�C[�e�@�\=]]�����Mf�e$��3Os$�������c��)J���hX��`��Q�LQ��M|�j���+�]��a�����6GT3����i/��N�zW|	��;��N���M�Z�P�p�=�#E�����V/
n�� �1gT$����Q�*�d��Pb����M��onjW}�on��]$P��Q�i�^��<��_f�g�A�M���H+�����]��j��3U��]���OHU�����������
�G�n!$��&�v��\:&�������P�3�]����w/$[�HZ��R�x����tj��)��*����[�{����a
c��h����Jti5��z�M��Ph9:|3���Fz��
��N���4:y���?B��4my&��_�a�_��MPI�T�%k�c=��
^/�!
x���7��fJ�D�&���>9N�����a�
��XPh}^�H�$�����K7KZIs\�*F�3��cZ�8��v�~:Q�C�GM��?�������2��|W��	H!�	�����4TW���pAJN-q�;�F�/�����'N�'��}8<�<��A�����b��q��	���I1L��� -��{�7��������~8�e��;$�)O5�r�a�i0.�-��L_���*:�f����9!�yP��u{[�LM���Ti��SP����U���N�o�T;q�8*��J�yf���L�2�_|
�YD���gX���GR��otr"ot�;����zC��{QWp(6��-6��'�;�	��gq��W�����`Y���q�r�@�+�5]�4�*�K+��R�9E�����U��U�p�b����<5���_M�^$#?�Z�y��I�G��B���aImT1���~6�M�`N	��:�s�������|,��X�z��?������F������t�[)�3�?0�2
}��@��Z5kA��h4����x����6�N��^��y�d����C�������@��5���	��L�N�N��D�ER�`Hq�.��X��Yy�����PZ�7~��+�J�%�2`t{�<�^�8����\TfT?��N��0���+�5�0���Y������tr$���\�`T��.uE����������n�nVY���W�Hfr?�2�q����O6o9Kn��5���2
�\`6���aet#�{�N�$���e�i�����#���T��������@����g�%�������Y�^[Nv�J�S��I�Z��4cH�KY�,�+�� Y����|ex�|��������E�\�{���Q���HTU'�$�VOBge��t�BQ����1���}���z6qS�i�(�.qv9�ans��Z�q�@�Nm���5��zR/T���~�}�����@�c!�s�������N���$l[�:j�|�����k8B-'
��
����r�VFu
�&E.��Fz{q�x���J�x�Hn�������P�`�t���B.����NWtP?y�3S������s������G����4�$��D� Q��.	��xwj0�{�$U�Yre��Sw0���3����e��7P���7����P=7W��6��m|��Y�e8��.�����\I�����
ZWE�]{x^�yS�Rx`nnK�H��!������������	�I�e$Pe�Z".�F��@����t��m�~���*P@����f�������������.�*����I ��J�^�*�|][F�.<��)�:���A��oa��_N-�����F�z�/����b�5!���(�-�0���y�4��9����L���G���'q_�d)I���t�N���-��C�OD��(,�w�7�u���E�A�����S'y'�9a��	��&]Q�����xP�U�����&K����$���$��H����V����x�Q��x��`�{�M
��w)����l��������j��m��i<�{_���P<�� q�90J���<:�|Xl|�'�6�����<��IF�D*��Q��\C�V�&����D�4#��P#�W0%U��y�0�FuB����/�"|K}]��N�)�u+���hx�=zl��y�R�������@m�k8���fJ���g������G��8I��u�Q��9."�!���dC�m���!-��\ ^�0�
�\W�E��;V��dJA0�p���ypU)���������Z��������EkEN$�L��3t#q��2�[VEb�c���>@r��3����R[�w^o(���B���v��R�����C��h>�N�v��|q�2Cw���K}��a��6
9��h#-�i�-[�"M���hL����Au6�nT:n#�����a{D�>�����S��{
����!2r��l�%�=����
�.e�:�O�����%U�����F��uZW�2�gV�����H��\�vw�@M�(t���+������[S��i/�"�9��D�����U������9�GQ55�	�F�5F�����m�{����/��L�vr2���|�����"���c
;.)���S�$��
X!V-�an��"r�f��"qK}�.���+�w���/c]H=$��������t �|�
�_�F����Z�0f����������c�s�~-�l�C�a�V6��o�~�17�E�~������K{n��ET�[�09)D,'��B�c�(n�5aY���W�_*Z��#h���7��e+�(?�y
�PA2����'�C�C�[{Vec�(u��m�S�tt	z�����J���zb��t�.�lF%A�$7jG(wt(d����������]�,Lz��U�*�8�
�����������zY��ZpJmJk��)���V�i��i�c��l6S7���x�k�$_}
�J��&*k��8�k�����h��x�vq�B~��^7����S"(x���x�����������HnU���J�.��X��B:�D���[��it�\F
�����Tg��L�������T�=�	����=���r��1x������H����e��X���(�cQ�mgSlpre��z���E8s������'�K�2u>�y5=]�����DF4i�]UAG��^��� ���%��iO����2zs1�j����zT��N�N<��$����������g���(���K� ���*���c���2~T�4b�!��`D���������Z�@���6�"��.��]�s����Vm�Y�6���K�$�T�:�V"U�!����G�s��Wz
��'�����2��,��X�����%q��h�����l��f��m�/~-��*���nB1fa�Y������X2�N\�J������Py�������Y)C7�%���	��Y����(U��
��.�y'��a�V,��m!���/�q��c����PNVIM����h�w\�nBq���L��wEU��� j1�!���0h�I9�
4��*��{�%��+K����fmc=����{��DR"�)���*U=��pqD����%2�_?���p����f��*yb7w�����7���:�����:p2�\(�3�r���6��E[���;d�/,*�}�� 6�)V����W0`R%�\�����3=+�)Z��������<eD�]��?E{��`~��g�)E��SE���N@�H`a�iJP�����������!����r�jP��5B+u��AU9��*4��X��Pr��56a��#����s��+�@kz����uY�4��x�ZVz(����L1��
b�@�KD:��"�����X��,HiX��D��k�W��{'O��:��4q�[:�R� ��dm2�,��
��r�r����K�c�AV���PR^��3�Z��=cq�s��yu�+��2���B��Y0)�u�Rr���GeL)��#�\M�,}���K�t����[�\�l������XqtbmiC�u`��%,!�X��F��'���P^2��{��+iz�������!?��n���`��z"�4B��0�
�����"iCp4���[W�&+�2Vp	��-~���4 z7��8I����xT�.���t�)�����)�56-���0�t<���2dY�"o89��5N����Q��6i5���/���D#"�})��73-���7i�`�I� s���4?��/��,U�
��s T��E$�X�QuF��������p�y����[-1��\�"�}��_\��%K��0p@�%u�-�_^(��8ha�����������������@�G5�+d��d�U*�q
�U�������]F�
.���s������q���T�MnQ��q�W��7Teu���|c2����!�Ka���.������=��p��.����������|4����V��]�N������2�5�2��^4CX�����1A�7����u�u�@*S�n�X���&*#�'�I1]~7X!��.�Q'����}��_5�2��N�e����c�+���[���+'
�e���\�����h��;[���*�]&�'5h�������|T���*�B^n�M�����:�gT��d����&V�����
:���&���N�`S��,�`�%��U��c��)��Su��6�R����
-��
+�E'!�<���UU&������LJq���!S��fz���k��RR�u^��X�3F��:�*}F�@�h>����>�}K��6M�x��������q�E����i��'�;A�HW4�t���`�je"eY�0��"�P�74�����~�E	dy�qkb��-�3�����-q���{0dRX����
�9����%��-a}9�(_@4t��H9��rr*a>�?����0b�r�^gh��f,�]��x�@����g�s��7J��5������q�����w"����w!wu��9Y����Z,��K���8��(�4yf(�^B:$6!g7���k|9I��(�&X�>n=��0���D���"����u-��|gP��Mfy
��'M��A����}
V5�L����5���{.	���H���L�3����J�7��"f1<pJ��-J����9=O�����CZ����DD�����V�����GjB���\������9fd�(��u4����?��������@�Xd�p/y�T~��.d�����Xn���VvS@�Z��4�<<�IZt�I[���3;gGC�S�w�����=�J�4c�������W���f�#�m�C���:0[��Duk���C6;S5%:_`�s��fhcT�B/���;�
����^�����]�+��(�����WuV����P�4D���A'F5A�UE�R���a�l�)I��;7����f��Y�C{�W�9�4�����Z�L�� (������2!�j�hO�!XT����%C��*"���4)�[�PM�
�!�O�}H|8���n���v��t�JK<I%����~��W��L�A�5�M���%��j?G�9������"���*6�v�ll,:/\��Q���2����)�+������������2��$^��d\����K����.9�^���� ���t�t����]s�%��2"`^U5���>#uU^�H�����j�a��6���*D����-8��9.���5$���.AW������*���0�����c��Y�<�Ig���M<��U��4^b���������54�
^q�������p�+�0����%�ZL�"�^+�1��)�Wn�#p�)��[&-�:�&R-��!��u�����y��&�^����[N:i�����W���=	�<��b%.MW��V��.���Y��{
F�M��������d��
�	b���C?����y'���l
��]xm,�(MwXV�s�
����F��I������6�V� !}��3H�6���D�[a}��=����~���tc�EI22K ��&4 �������#�S�P��2��.�QVQ���2O�S����;M���gC:~`�`��a��*��7�k���.V3�����a����8I����w5�f����J����V�8Ax��������������6,j���1e?�xY�:�����R�:f3�TeD�L�:9V��l��/���%�X�������)o�w/�3fE4I�o�=P<~����5�
�_{�0�-��~+�����.o��R�����N�R����B�\�� ���YFO-�[c�*�7���b�t�e�i��� ��y������Eu��-�A�Q�g�n}����2��$�<�Xe���,8�������mg��6�fM:Z�4�!vw�(����3�\b"�l����^��a�%L���s�mH��nB�%�}N�������W��f(��Ti6M�������/�L���?f�D�r���c��gI�<2����`iZ*��'4��&�L�]�b��5�b�@���|�����g����6���9+}P�}�w-����#c��ee�"*�����WQK�=�]v�vCn=�[P���
`zz��v
}�=nY��a)�E�:���&i�lTn�^5+a��%.�E�7��RK�q�Jt�������d����M.*�9��d9�t�&��������>s~	
,�M����W�wS��_<%S��O���
����U"�z[��)��E�f��0~Q��i�)���
���9���h�R��)c���X���,3�4�Q�;@B��.4[M�j�YF?�������i���������#M)Q�^���F��d�,��C~A�����7�>�wW_�HC���>�>[����N�d����2�����������(V�B��!mZ����U�P�hz<�����dpwH�=���k�p�/<~q,�t2	mpu�*6����d�M���m���d��02J��� ���$5���}\[��;$��HQ��]���<��CH���e����6����/4d�������pc�A�<�`)���0���6����WYY��P(�n)�O�&-d��A�ktNL�u7L�!�VoU$=���@>`�!�����:��{��/�=�K*n^}#@q�L�=�$�(�Q��gC��`t
z��p������������*3����7J�[m��B��5�Y=z~'��������.��8���C� �0�_o�����%u�e���;�y�9���>����e�����0�12��q��a����R�����5��gT�G����
��"��zS���L�(E�A��bb+�F�zsZG&�
>��{�d� h#��3������������g��"��X��
K#��]������:�c�l7�g�����h��x
�����;p���!��}�R\��"Y[�N�0���}���zr�����Z#�Fmj[�
���q�%}<�� (�������E~��#nQY�m(���T����k
$�&�r��k�C'�d�gM�`�.��� x��,(O\4�M���������qQ���
�U�a�C�]_D&��A����L�;T� 2��O��a�$Q^�����K������"4{lN1���������p�\Q��'Ve�����m��5_�"�}��0����AD�0����� %!/$PE�(VxU��0�[�1�'_�����y�LZ�d	����0b�ocL.��r��Y��U^���V-�i+CN��|"��I~��Gpm����t�����+'3�-PXl�Q�A0�Le�]����*���A}�1l�Y3��;Sl�/�2)LD�.����������bJ���{���I�|��X3g�D���"����h�.sJ�sjL�����M��4�=�q�x���j�_��+Y����W��e�g��qb�������c)C�n�SA��<����3��8��@�����2��'ZmQ��@�L�$D��'g���gC���,w�����h?��C����+ntSlP�<P	y���*�A0h����&2|LH`N�a�;0�
'i�Z��s�j�rt��(�X� �f�u���,��*�f�
[�-�|Y�UR��;t@��$Y��>����%�2�G���q��u����<��W6�u��J��-��F)a)A
y��
Nm�h(��l��.<C(�S�*s��A����uh�!2��
R*����Vlr2L��E4��L�^�~��a�������<Mglgh��$�c��A��azQ��k������#P+��%�Z��������%�N�H�7����:������������g�����?��X�~M_�<�����	=[�'����;����F��?�<k�Ih�x��r`0U�(�c�q�'�/'�@��Y��A��r��|&�Z�7�(���G�p����Ax"����N��cg\Fe\����;�tmyVM���s��'��OFem�U�8��b������`�%������9b��p5L��}�D#�U<]KTXE���6k��*��[v�p.���+O:�\��C]��)�T�u�1�9�{u���r�x��'�X@����d�U�m�p��c)�A���@�.P�^�glBk�i�0�-�4��@�Q4EU���XEg��W8���q����.�����1f^����A
7y�&m�r�i$C�e���U4Y�b1�*��U��f]��a�i{��VspA�P+����%/��y�*�M�����7�����i��X�1��i��kk��T,�� x.����U�\{���e�	��ur����}QY��/�K�Ef^Uv�u�n��e�)Y��5nI�p��=���y���oX�� OT�y.w�l:_H�Z�#������H�S�7x+���'@|(������x����4[^�m�4l*�
�����(���i������?����n�3W���:�v>�=����;%,"8���V�6�V_�A���%��r����y��Al�O��Q�M��L�����b�7��zc������R�/PUJ�=��o��i�Fp�0d6B�L?+"����-�J�����&3|��<��G����dJ
�6�^���������W��k��x�B��e&�Yijf�^���*�q�tc$�`�����A���5L�����*+��Wl�������K1e���4�V�"h��6S�?����Jp�6�I��|�^������E�jR��\~���n:�Bs�x��Pi��.X)
�
��T�T=����'J4@ng9w�$��������
���6r_�yKZ��kr��s&:���@��2�.�o�=$���K�]����b'�����	%g`�U-h����)B%����n�Z�5�����E3���9��e$��M8-PQ�|�����hXy
%�i%\�9�=P��������|��d`K��~�v{8�BQ�p>�����N�"��m�,���6�0��L&Io�U��� �cu{���uS���N9����6
= �����Q."�0�sy��-�."7M���P��P$��e�R2HU)�?��o�8@5t8���r�ld����p/���a_ev7htE��5�L���iC���6.�0	5�
2(�+��ed����jp���
H���~>y6�� �����,�����30(
[2i`��_2O��V&�����P4(�z�������R�������m�
/U'�g���q}=��,P7�^�ps����?c��C�?h���Y�5q���6��6����`@��N7�jt����*W���F�al�������\L*��^D��P������d�e����E��=��\�1���j&�r�rU��_!U��f��|����n��M��q�ffR�j�e3	��5�|��N��T�1`Gc\����na�c�.���u~-1�/zN/L�3�E���������i[ E���*B���������T�UV��%G*���(J��G�^�O�����`}��VreGTU�k��F!a�������?y�[�4�k��j��zb����:���\[|u{U�@��2�gu�@����u;�����y+����(x�A���g�������$�~��H(��O�����H��0�^��a~��>m���|��nB<�k;Q$���AEw����hs�bq<���3-������$�����|�H3P��m�����}��!gNHND�T0U.�C�f
�
"�+��L��U�����lyuN
����p}��,Oo�n>�����H��7=��(&b�BC[������i����7X��T��!U��5������b9g��2�3?����Qc�Z2u��4�[���Y� ]:�^���V8sBf\�Ie����e�M����f9�l9����U��U���M>85R��I|	K��)��ZK��*����
g�d���T�i��y������H6��'��T��t����D_��2�K��T<,MV8W=�}���+�����qVc��A�\�5�/��;Q�SM:��[�)4Ma&a�He���G%��t��u �b�J>>�4
Y�����#�!�>c?��1X������6�������Y���A��:).K�J��������T�6����^�{+����-wr�g+�cR>2LC�
�sj�r	p`*��a�+� ���iw8<��9�B�)
��)��v�1/b�^���>r��ef�(Z�����.;�����5P��q�.�t8��yhJ�~�|����4�N����>�%vB�<L��������8	n�a�0�����Gu��k��1*�/>���a>��R~b�s:�u����_����g8����
;�����p`n����S[�~���*�[��UHc��m��d�K
�
�VO�6j�dP�p�02��e����+3�T(e�:�f.o�[�����)3j�HYW��O_�!�Ve	%��B�uT!m8p��D�kB=���lGO���U�a\��J����b�"ZO��H.���w��cbw<O4����y����l���;MO����)��T�r�xe�'1;���R�w*��tLS!��`O����H%y�qe�g��n��=���gV����LA�Z}��P��n�_!�7���h��k@x��
�/[|n��0��,K\s&~.P��9P�Y�7^�<
��u3n>(��*�A�(
\�Vw�D�����i�|���9�2yd����O���'Zz��vxb	T��+���f�'5��6)��HBo/���e�T�p�����������5���#S�!Q^���"�YG��]��<k���Hi7�}9#J����i:)OuJ2���t�`}��~�S�
�P��43��{����./?
V������4a�*�q��f�MQq�����j�� �"�����I�����{X�`\��[��F�������9� ���9�Z����TiDFNZ��M��3�S�q�w��Y3�&����9�6(G�����"���9�]�~�e���Bm#����1�N��w��%����y�"�Y(_��; ����@���j�i�
���Qa�����B&_l2�V!v(��N����l��e)"j���{q<������
nB�rDU����bq��Iib��5�oV�3�hq�4M�����(�
�����nJ�t��U����Q���RC6���|��M�2c�����]G���U3��A�Y����thcwr�K^$��8��0{2RC�=^���j�.,����`�N_5���%v�;s���M3��J,e�/X����i1����<����O��&����g2�������y����	V1����,����q�`��A�.<�tV���[�T/z�F�����N *p����y*��6y��\)����m���)���78���Z� �eL�t:/U?6��({���5��4u��&8+�E��XKW�BDQ�����A�%b�v��Xf���~����-��� fF��s���T���Q��^��>���|���U��f�
af]���3<�DK&�L�Y���������l�[���c��6���V��}��1#8��62P��i�C+����M��C+�����Vp�����L�����8����(���������Y�d��E��9�H�@Ef�����i�*X3�,�Q����q=��r�����
��q�P1[� ��GVb��S����/-V��S[ez!JS�q�L9�wO..���EV��I�
�I����'����EK�N4'+a��rZ�+���%�3(��	�;���P�s"�<��L��A!���W���y��BC:���8�6��ww�:��^�����,:�6�3f!d"���	sK���3�����C$zw���
�v3��.�s2H����Q�S"

*�����s�S�G������Ly���w��f�_��1�@}�v���q8����86�K"�_1%������%��Z�������09H�'����o���"4'��o��E���%A���i����FWb��a�J�@�%�q����������Y��,J�d�����8|�TX�v�kJFX�\�
LA��x��F�`��7/�~l 3M�LF��d��@�/�<�
k���^�D��6$3���Ye�$�U��XR����"M�8WF|pjT��8}�3��u
���N���l+U)�pk�W��Vybj����vk��M��{�h�t��<��.��%�!�-��� �}�uT���$��R��\�"��z��}�T�Gr�
����d����-J�sB>�|U�a���4H�VAT��4����:���{
�fm�����d�^�������e,�M�����;�Q`���*���U�C�M&'�L�@u��?���������d��rR�����.���P�<95h"b
��N��(W�Z���V}]���eYd{�����+u%:�f^7���Y��%�y4�@�PC�\'C�M��qQ9P:8h1<�E��HzTE�C�(1<j�T����}�����u*�����^�b�>��&N$}�������=���KD��	e�!5M�{�h����e���:�2�����-�Q{��tZ�&�Q�U/�gQ����[?N�P�
���BN�8f�b`�0��o�����J��\��=���,����T�	mM`��O|7��A�e����L�u�;"I��A�S�l	G^<N.�3-j"�K�Z<�+GK�<�������N8#:A�J��WM�yq2[	(��:���r2����D��x����n��3K�P��=,�����Ls��L������@�K���!c2�"�D�@�������UK��W�����)��-�p��:�n����ItF\���p��u\��02?{��y�EFv)K�f����j����d{�j�����@:�8 %4�����t�R���x�b���F�C6t�Vj�S�yYg!�c<���N�u�������j�ye9j,���4z��y����PY�9���`ug�p��7K��Dw;
���W�g�.L���*�zZV�3u���Q�Q�a���TI2�y������
TY�)Z�Z�QM1,�pvL������w�}Z�-&#��R�]������d�k��qE����@�Q���Ld����K�z=�<�aI�	��F	+k����i���M�<YQ�>����.�He16�����l!v5��\����z�O���������|��	�"|������808��,Wk�:'lC4=-����`Cl��@�:�,�0�>o�U������Z�U���T����o���7B������M9w�T���	��l�zl
"��KV���A��u
�J_�
�������|�����X���Kg]�����I[�~��x��V�^,��xh<Sy��G��p��j$���^GD&W)Z��O:���,6�(Ox���G�+�D���VtT@��C������h/��CA�&�����*��r��&T_ ��q�n�8S,��
����Nc��sA�;���%�5��J�4���|b�]pf���U3��"�o��9
i�Cy*�L�}_�J4�%�� L5�B:���K�i�_U��7^u�m:��c��I�}�-T�6;���O��D�&����:���O��I~e�
�����~�����qet��)u�2�V<!�#p����������E�c�&a��^8�

�b�"m������Z���h"� ���A{���d�9	��g�HP���D+��i �����&=L� �D��C�]L���8��}8�V�j���-�5�z���S�.~�<����,�z�%�[�*(����Y�m.������o$V���M=��<����b
�
 !B�#/xP;���������8�7IY���\�Y���tfT��>Y�8�8�����3��
����j�:
m\��U����%��#�������h$��|n�'�$�z��4�M��]��1�V�u&i`N��D;M&�����#�4�������
L�?v@���`���A�������D M�y�#{_��4L���&:&����2���`+���q��#�-�D�����>�F�^��"B#v�@���"q"��'C0:�S��80�6�H�Z@D0���<iXV%$4,�	�s#jO<����D�p>�:��?pJ�|�5�T�6n�)�k���o���V|���D��B����R�������we�"�R%M��:X�����f���B��x;�C MP�����c�������������t���Ip�.��O���Z�������"T��F��`}���+�g\f%kNW�b����z�.�����L�bB��a�
O����x�A��C��~>�f Cx5��<Ehh�O�I���=�>7�������yV#���������y�8M�uQP��X��S!�{(�����:M#�88#�$+��*�,�w������L��F{8P����iHO����n��J�^��B����h����g������`<s�9��	g�S�W��e�8(@�;ege����u^d�I�2�3_�:�3�2d�v��;��g����kS�)�3�r�����	5���1H�M�}��2���������M���E�d�z5�4�Q��������+��p���p2H��nmt`lr6s$���$X�8?������5�<�V
�"��1O�[jZ�B�ie@
�Gq���Q���L�S��MM�GJ46���f���X�RC��p�O�E0��DT:P���@�26wi	E�KK� 0|�48���V���E��n�FA�R�c�Vga������)��GV��4�����Su9L�s��\u|����aW=��X0�AP�����f4�u�%������.Q$�����O	���%��R�1N����%So�Dq�@�j2j�{0B��-$�,���H�Ll��+�&Z�n���X"7���d�&4��~Du��&�+��+�6FT��N����� ��e�z2(�����$,����O��$ ��@�oxX�c)�Er0Ba���V�G����s�X��N����^'����|�������w�D�)}�`��o^�����v$�!W�k�k��_4�W6�����*;��mu���b!��0d�,l�5K�)#�N6�y��^�*?������_lV8�,iFaN&UT����RB`�hc�t8/�{�����x��@=F�R^��H5�(q/���3�������>H�W����:hay)�l��IG��iEL�?��
�n�NeKE`����t8�Yx
���kV��x�/��2�4_�P9[J��F�}�@����[���yv.M��D��b�d�����F��0������b��&��)9��d	�^��A������V����k�w�k{����J-������Yr"F��4[�!��
Na�������{L�Y��[N8�t���%&�"k[-c#���+��k(�� �������:dA�U�O����YhO�&�0kA��q��E��O���8U�B���)�-���3��`|��L�����)K�LF���U��.���V#WQ��=��+���+y}��E�����@#R|b%��N32Tp����A�Y�b[�����(-��.�J������B�i�^����1�G@��
j����Td���������� �N�A��`����L������f�-���?&��]2]@L���t����VDU�:\R�h&���Lo��}�f��i?v�1*1|&H����-H~���r�������n
u�l��<���b�j����9�W/7�������_��^����}W�g�����`����,������O��?�����������-7��� ?����OUU�8?P����c�uY�k�M�/J���^�������S(�����[�Y��'�E�0!�P�
b�wb�����fF�����a-��Z��_�A�d�@)���U��!K�}����
���@�q�}E�Y��BT#�Whs0Q�Y����dJgJ<��@�YQ�V
q
�l>�_b�����i��G�h�$E�	��"���1�����]��#Y^x���KW������j�����k�
#"�)���m��5g�m�*�}����B��c;��@F������[Rq����{)�l�
 �{y EUv8�!��,�����nE&1j]����<P�o���y���:M����j�RD�[U�J����c2���L��/���&|o�����en�P5���5�����!�[W���A���p*�v�o��{��'"s���t���K��D�u=/*X�Y#ti"*p��2��^9hX�V��RN�����'y�$2�&�71Ys�Z�"b�@�
����BR*�yl�E�<h�~����aku��B
���s@�m��\+��������3r�0x�
�����-��P�B�i��#�*���2��98f[s�].�<+a��P��Xk)�l[T&�@���-�*�}���a��W����p��
�c��v��3��w��W1����Dhh��G����l���
�&�n�[H���qn�1�������.�H3*9!+��]��8~��iN��7����X��F�{���Q�=��m�;�Nsh�Z��|4}"�f�e����U���840C����M����x�<O�t*;�A;>M?���
�<���5	-4FQ���&���e��P����S����O�����M�������M��`{2 ��a���=vM�����D&"��K�C�0����>MD[���n��6,�I���-�V�0�8��M�}!^�M�?���ud[�z�S��L"����.9=xC;�����5��<xD����?�T�������8�B2�z�{CK62���v|�v���vy�Bm�
m/{��EG_h�q#Cm-IVI�"�r��I���*8
���O�%fZ8��6�����9�=�����L!��������Ev�J�R��u "����F'��LjDh���O.���a���u2��q�J,�>#�!m���f��m�9m���#�!2}sv����0>�q���w�!��������� �oh���&�
�_nQ�����F��'(Pa��H*��J ���l��o�9��&W���jFs�mTX`L,X��@������W��Tq�sp,=�hH��X/a��A���D�Q�\/��@f}�>U�S������,���m���bJ�$���d'7h'���7J b�WC�&����SbtU;�L1�(�D��^�v���\���V��"�G�Q���qU^Uu��A����o�F�Dne+r&.��_��!."��$X|i���`=��}�����)��%i�N

0+�����q�]U,$b%Vs�J>�:k������HD�2�M�:����Y%%;!����4q:sB;�i$����?yD;m�<����Zx8�6��v���i��h��������f<sr.�!��2��ng��G�[t �XD��H��E�2P����O����4��������X�r`������X#������u9
��C�U��c����HV{�!���as��9h�)=yDK�&E�H��Z�I�L��-�P�zn��C&��d�
�q�;�����b���N�%�%"��v8%���#�=�O��1�@���q-����x9d04��.�(j�-Q:P|A���:�&-f�$����"�����]BEj���R�MFC�q-��.a�{�7�x��t���7���
�u����M	��XM5����'�94r�E��(t��h�cFkK���!|4sf�4{�f6t���" ���a�7 {���`%�����})����#�Xd&��������`>�����g�Y�����T_����x�+X����8�/�t���_��:�m�|��&c9,�]4!	p�B�hIx����[3��{���t�tk��5.�i�8����va�L>Wu��W�i1�}w�j����i�@4S
Y"��y:�0l0e>����������4�D�i��F�����}	�����i0���<�.M��X�=T��HBQT��R�A�h�<��,��d��C]�*h@���7�t&�D�YOW*��������jk�����/���x
&�Z�?���=���?�����Z��<��Sz�elpz�p�
-�E�M�
m�<|!������%�&��&vG�h��'�czE�hOO�i����>�[z|n��n������%Z<m���D|��� ���������#Z�d�w���p��L���Y/�]��������VW?�6�mxH&'W�@1��7���ugS"��M��/��6g�Ss�2h�t1��R5A�|����a���OR*V�Q7�XH�*�57�
�����%����-0����u��� �������PK�D������8�"�U)��y{yAY��:��K��j����N�����Dn�Y�	�����^���
�9�C"�}��a�1|�6��23`����\�4�Z:����	r��K������(����H�#C�HWV� @�^i�"���'�Ay���@�K���#`Y�,�����M���&@e7�(%",O���M��@���cl�W-�s�Z�\4�f���~\���5l2��do�M���;��u4r����v�;�s#��u���Pk*Ld�5���W'�X�� �*;�0
A����z|j3���7K�p��VE���:-���:U."��C����h�v�K^�L�[2���l���Xz�@�UM�?��o?�������$�%�5 +�kt�����q���q�$4@�O�O�V�	��`�-�5t+A��3����&��a����3L
���F����A��0���F�J+yO/AQ��"�C{���*��8a���P������Q=����0�g
���>#D�%;H"��&�!a&>�l��aj�`�i2d�V�,��k��t�]�z������o��������o9r�QL�b��2����uS2����
x��-I��aF��ie�����$
c��"7�l����7N|3�<
In�y(3k�8�F��`#�E.je|<�����nf�(���f5����@1�(�`!`�bZ}"b,��@
�fQ� x���mY�(�K
 V}�����A����
-=m"�IA;>��Jk����a"��A��������XD��	���&vb������q��G;l����<�Ts�;���T4��KfIy�����l����T~~uB:�s�*�"���,j�66PJ��N���UF>����������O@fMy���/��(��w�;�F��A�2��d��I�b�����&��<��Lfd;�p}R���hn4�6���[������x��F�5P��.rW
�����)�r��,FA��&tZ"����A[$k�+��pi}Z��[��������S��x�U�N�D\\���Y���T��i��2{����-\,T4�z�U4��h����B^��R��F	<��v���wS��z%�������v�Y�Z���$���'�!��6��>��Rr;��^�!�rs���B3Ni&jR��E��fy8�2tS�2RQ%��WF[d�[��D���g�b"��R������T
���J�1a!�E�S�A��avRg��4�v�n813�!2�\�������@����?�zp�#)�Y{	���E�u�E$a�p�V�����LBy�u��zcXGd�^5��F��������]�K�$�����'��S�K9k�@���p{i�K���Dw	PQ�����,/!�\v]#�������W&�������v��G�\yqp��7=\�F�G���z.+����_d:930L�+E��x�"������h
�hi����
Z@1�Tl������.�F��������\�����{5= ���yT!zW�V
�P-*rQ���<nA�a"�~�%���X�.��u%�>�T,���M����
��(��Yn!�|�2
�	��T9k���*�r�8tM-�iu��&���ru�
E�s���ET����c��%Kyo���5A���vr�z�U�� �V2�	36������h�a?[�!#A�)wX1�Ev�����M(����C�N�����-s�G0���C�h�:q�k�����}�`B����
�d���:��P">r!�{��GX���E��A����V������j������NG��5e�h�Myu(o���)���q�U�z����O�Yc9��NV��"����P�	���5��g�=D���?Yu���1���P�2^�'��n�Z�������XWU�J�z�N��[horQa�7
;h��zdDd@���	�q���j�Y������P��%�,nr}�n������e��O� ��%�L�E_�}q`�?xK�F��
�u��#l-o���Q:P�1�+����r1���v�z�1��4�LD�u�$����hP�e�h�F��d^��9U&���H����:Q2�S3fD�8	��A��j�|:�7��l7[���,�e��)dE�
�*��'b��Fa?%�F)�v����5X_���� ���v��JQ+C0P�E��",�-��`�9�\�`���Xu�A-��a�<��PVjq:f��M�,w������o��
���
m���g
Q$��h�b�HB�[���a�
*�[�]����M11G��{Y�V���QA�gUE
��4m��b��iP��*��<��"Nf<��F.k�q��q'O��88n�A�A��*���T��1k��H�H�
�H���O�f�D@�[X)�_������=�*A��V�-����C�a���|b�d��D��X�l�������m�@�/9X��p�P�`���R���k|q]D*�`-�WQ�r�>�l*[���n���+#��Vx2�T�R�%�G��Y@��K�������o	�d�A�Q�y=�����Z���5[�E=F"������L��������&�!:�q���V7;F�&��T4C���["�s�����;�"l�s��%%����S��*�&�mcT���.S��8W`�1�C�� H��
2rp!�&�$�#�%s<:�@�-4a
~��GPPi��{����
[;1�X�y)p��Q���y$2��<I�D�A�R"��TZ1T%�0��L���L��I~����4��/w}����1J&�S�N*��C������ |��P*�3��m�
.��QqN^$����24�=@�xb�����{o�H"lR�Bh b�D��]V>��'&��jP����<8DE�$���2r��<�Y_V:�jQ��bL��
��S�����9��!v]���~�+���#
������T�9{v"�0<�aV���q3Hh�z�d,X,����K��Z�Yu�2J���e7|b���;%�Ba�`<����=�:`�5���e��C�l�
�w���Vd&�������S�d�'����%���np��X{�i���%�_�x��A�\6}YB)�`^O����PA�������X'E���t��D�;�-(����2���Q�.���L�R]����	�D�������,�"���U�/qj��������I���8@)BM���4?5Jq����%w��Y'��h���B�#���PVn[�B5�{��P�����V7�Q��y��1j�qq�N�M��ESaW~0�E�S��H����:�|8�����z����e����C^��6s��<���<���ef���c�a�P����$�&�j����dP��"����c9H}��ot4�HY����&s����	��+����4��>-|P�����@l��4�,�"�>|��)MH��.�$k�A���<:������o���lJ�������M��,
�jKrC��}��
J7�SB�(L�$���
�@T���Z����K�fg��E2�j���kK�k	��[���e��*,�dN}�H
�h������L�����TM�,��u���TR��~H���s4�3b�<�����i�9�>����?�����%m���0G��Q���U��?�d��P%�����.���1x���+������"^�:5�<�ky"B�u�&�����a�D�*�;�J��$B�}���!y��f(�����G���V���>�b�o!��b�-e�B�d��t�hip&���;M|��]������D&��u�O�O������k�h�v��8����=�S�����7@��CO��'����&�>�-|2$�����z����:��U������-6�h�v��N��n�/r4'�D{��$���=���!-�����L����o-�w.�����}u�&;����0o�$���44t���8j=�"A%���jr� ���S����M5A��SQ������V��4�����E���{E��5	yt:���%��@�����f�N��1t�%���@).�-��r�L-������[���v.�|f*�+��yO�}k��N��#�V�|������{Y��j�s#���i���6�@��&�U/f�GGF��]c�����4H�Y�T$5���N{CT�5�N:��7Ay���gT45H.��������%T��y�X����
�FP�u�\22^+����q���ZvXx������0P���������+���Bc��`���wo�����(��������Dh\&e�����R^^��
`�6��|x��'
j-�$#�}'^�rS�f8�t��<G\���������`�1�i8iH���R�r�Q�}��������5�X��1�6g�(�q�����x2���p�Q��"F��`���P �� V�����/�}OQ�r��LDm�*�+�����|��v�d�k�ST�@�������3@#�]�a8��0ii�
��w:�O&�2�z���/d������s�bW�N�z�Pa��������(����{����U���S���2ER�����&��%m����$q}X������y����i���l�{^p��J����m0����2���(����L���w��Iat��<e����OX��X���b��`��X��#������
V�Je���+F�T������V�L�0Z���~l��E��g�}V�:xT�<�^���X�5i���"J��<p��[�b���*�@�����B&�C�Cd	�zN-Z�hK�id���#"�`BE��GS���i5TL1�����h�a����0:�
0-� ������[����A<;���c��K��\G0(�rq�����b�M����N����$����6dS�5�D<l��v���%3�s��4�0��E����"U�"a[��t[;���|����$H��L�2G�K�aF��r\�I`]�����&�XrM�3�3��mX�����@���p@S;B�������|���d8�lq�u��nS�":�z��b|E%rM����K~�o���������Ld�j��-+�iS9�/e����������3wx���8����������m0�je8�Q�O����E)��S�]�����zSq�6�3e&��0'l�xY�Q;��P�5�+h�����
��W�������$���W���Yj,��j��&_�&+�~�"c�����?��"����p��2|&�,���$��^��D7Ym���c~�3���w��2 {�<����O���p�$�V���'��~��\���gH_Y����}�)rx'���o��/�#5�����0@r0~�����h��<��Sw�KUV��s��yu�MK.V���� ����ue� �#����d��Cs�����������"���4�"��{����	����+��o�'�}<�_.r�2�������2��x���"�����|�;���b��/?|�=���}a��A�/o->�-����'M���r)D�-���
���k<#>���WX^"���^��,�~�Y�f�Q�-��{�Y1��GNx�����A�N��L���j���gc��5&�PE��w�A�0
k�pP�5�j��A�:�qp
��9P���y���Xy��[��sdY�$M�o.����3�U���k���e4�+�������[!7��kX*�o��wch��U	��P�b/����� l�,c"�x��h����%��mS�����n��10z��	2�@�2�`���x��.���q�{���0�m�o�Mp��kH�@k�&��
~������<?Un��Pi�2a�UNMoY��
t]G"�<���X��U�������##R�%�M�Jq�[PW������pDne"O�{�:3�W�H~��)������%��5�{	��jL�(oo�L�q�����]���8F=��^�i�X8���;?>2!�j�	et��Q��C5Bf�&J�(3�*�6rP�S��HK�4�d�u���[q?N,<0E���mF:�g�7E4L���p�+���@"<�~\4
�0�A+����y�A�(Gn�������D��� �Y;�@,N�M���i�P	����x��s`eh0s24�������|%��,���NS������zU�	��A�����4h�cH������9����?l6���T6��h	l����f�L�t�<����'��������?A���|apr��7�zx���,�r�����U�Q��Hx��
Ec}������
1����Tt=c���Uc�����9�������uf�����0<�����|�S?��Gm����<'���]�/�s���~�4�` _�e��Y�'c}��Ng��P�XI�a�<�aJ��I	���r�=Jt��<�����s��@�Z^i�td��I���0����� �s`���u�`���z�X�,Y:@}��`Z��UA<5#B���n"�R��K�
�7_7�Uw\*��-l���a������;�6�N�Z��$���z�A$��YY5/a��m�zxZ�5�8C�\]a>���}�[����7���AwL>��
sF�<�p� x(2?:�z�d)k3C`_�@V}�`YBX2��5]7(����k�/M^]8�������j4Qxq{wV�`m(���H�_<@y	������W�76���?|�uCS�������������t��F`Q�%����U�p����y��L���a�KY��f�����t9H�vNI�aqR	&
�
��/���MD[��"�>���t(�X��
+
��7���Bb_�����e���z{CR�:�z_�����e�1���}��h�3t�i��4S%o�$��s��N��R��B�w��3������m"�,*��Z/����� 2�aMv������u�V�������L���������i����-��l������������F�r�A�-��O����M�?vm�d=1�:��~n��0����hA�F��Ih���7�l.��&'�a��uxTj�{ \�-�����&s�m{�D�Y}=���u�c����"���D�����F�S"��rgP	E|P
��<;_�7v���!���A�k��?��P1�������r�����R���~_j�}��;����G�����/	�#�S�M0����@FK����a&�MG��pP}���}
;|c~^�]�)�.,�k1����4�0�������q����7�5���nY���^�_E&,`{�&dP�B���9pQ��� �NG��`��
n!es��)�����.�^U|��84�4�\�E�l���I�Sa������$h��F��{(��v�D��Y�.��1���~��6]�������q��f�Cy�S?$"d�2��D���/{Y�;Q�u�L�0Z��T�������7�����q�^�?�)	�"��{�X*>G)����aA*��X=:7 ��F0)$��%��������`b����8k���%/�k 	����Z��8h��QD�����g.0��N���oX/u �j^:��!�a����Qa�~|�I�$ymU#�q<Z�k���Z�r����+�����?@�YF�S�wL,]j�]�xP�r��b�(D�J��v��p.�^{VlX��7S(�Yt�;��c��%�������em������t���;Z)^<!�"`S�*���{SA�.)�
D)^'��.P��K*b&G�:X E��8��p_���B����@00/Y�}\��dyH���I�@)���w~}p����K��=��,��f5�#��$�AY���T���y!*Y��*���9a��UA�2aP*�p��P�O����hI�A�$�:����)B���\j�yr*��W&f~�:(�Q���a�b2��b���`��J���k�`6�5����zO�7��!
�:T�%"��(�]%�|�72\�/-~��)�EC�3��:q����BC���B&�NMB���g�2�IG��013����ET����9{'Hcha?!�?�#3d��4u!*R�
�P��,
�T�!F1����5%����A��$q@��nX�'d!3
%2n%$��+������
:��1�f��8�
�F� ���>������5q�����B[` �5�f�+,�j�/1�P=Cte��*A���X���w�hMu�CQ{�q�0������1X���V�?���%���j�-�8�����C��0�L����&.d����[eC������\9\�~��jE��&�.�>&���Pa��g�U!����^���mV*��f��ID4Y��&�h-���V�&�<������1X�>���/�>��_�_��?��W���5���r�� �J������ }�X��e������;N9���-6Vvm�����a?���?�|�I�P+�,�m�$o"`����-� �	&J����O#5*��$G5�-��U����4H�uPfm�;��`�38����)[���L�*�c`�n��$��G�h���Z��,NK���7��h�>9Z�G�h�i����Q��<��[��t��� <^��&��������f���n��/d���"o�ts:D�v:��w�v����5���mG�h�G����$;�������D�����=l���9�/�ci�:�v�]��j���{�r�xc�
��M���_���R�(��o`��?�v���
��a�w�n�f��c��!�E'O&�SG{�R�����;4��iVDU�����cjX�����7�i����5|�p�1D�44Se���;m��DBKO�������������=����kKcS^E@;D�D� �����!���m��@���%���skh���6U`��	����SaHhh��/��3�@4����p�
�4����EC3%D4�;����-�������Z8D^�B�s��L=	������>������9�z:G{����
�'������FqhX6j_��)<D[���+��a���R���N����1
�wzJ���~��nLek��H����n����o�4E+�H/�ei�M�(44�����H�0���hp��A8%����� �:�d�fqd�t��
�Gq�����e��h@���6���+�W��U	�h�P���9h��t}4�\�!���>���]X��l����%�I���/i���O)�-iA���f�1h`��+X	����@�h���Q���
��1XuN�d�U]Mje����9H+�ZD�g��AX���b]u�h@�RO��b
F�,��7�������S�D
�*�J���0z���S����?>����Czz���<m���h7��h���)���O���-���i��@�n�i�������6N���--�����wD;��iC�FKv�x��a�N���=dD���w������&�N<D������u�h���a?�3��Oq|�}Pa[k*.���H��-@���gMn���V�e>���r��"B,xBaf�u�w���)M��Qw�8��u�S1�oU�s�c��@�\q^�B�t���e���Xs^�5�^�-�y�Z"��
s3��aLZ�>�a��s}���e,3n�a$+�d�}����
�.i�E�j%
u-h��������E�����=�9���Z����(=�g���Pg��2�/���#qM���Y���A
�_Q�/q"��|nl
�����:��cA�La��.�����@�7+�Y%c���j��NY���f�(�t6,&vU�U��:g�I��z����f�
��1��q3�;��LA-��	7����sK6�l��m;e�q��������q7�#������"v�5W4�&BA�{\Yb��x���6��������<���U+���$v[hO�����v�%�u&'�����C�����=n|�HZx��\BZz�ch��n{�����Qh���O�\[o�AD�a~e���P����gXC���Q� V:3^��������`p�h�8��\��?
K�#^�e��
��dFn��c�X[ba�yC�`���*���:�-��uw#y[(XB��6tQ�/�qfE��<E�>}2m8�h��4%������!w��qJcrG�������R�D2\:�v�@tP���a�Xs-%�Y�|W�v5,��(q�������@�K�j{M�0��?�^e}mdx�����KG���AM�gp��eX������*��(|Tx�$����M2�iuv"���3�4��	_-��80*h�� 
[�����.*��P��l{�o�I,1�0�^��"R��K_�>6sq�Z�	� =*L6p���e@��e^�G��������,��5;����6��}���@�*�b[5A�5�����~�%��@��o���J�A��o�W\���O��K��������7�gX��������o6��is|<���S�������o��\EX��3���/�o~��j�[oET��W��G�����_-������y��/9>}z��v���=���6&��O	RWmwnDk������% ����������nh(v����a/f�G��^N)'���8nj�rH/m�]}��A��U�S����~G�.�
}�!��A#��M�q�H���@�����7�����At� �7d�Y����[�y��y����{G�p��$t�M���5��*=y���<�q�����(K�`�����/����O��;�����l)[�_4��a�sR��n7�-,�g�����6v�-e�������]�t�Hx�O���w����6�O +��$h�Y�O�$�+�P�V5Ixf��
�����7$��<jC���jvs#a�Q�6����-!��g����
O����jC?��(�� �KT�e����~��C��3��O�{����E�9�����u��L���A�;�)Q�db����X9�i�<���6���;�E-5��O:={�c�h�%L���>[z�!��#_���]���Z G�u� ������M��8�[D{i��2+���b"��d�]�?�
%��{���
�S�qsjoi�������'���+.�TFDyE��/���.BY��ee�[�L���R���R��z0�����n��"���lE�Z�����;_��D=��U+�Q��9�
T����p�19��	�����$<����6�r�����~�]�G��cJ�����|k�A���3Q���Q��=�E���#h�CoN�;
�8-x���u�j���<O_��0����-(�THc(�mNn��cXX4�,o�Z�������C{���g)3������	����n�SV	L�4A{	�]�������A7r�s}GK�kF�2��#�P�BLx�g���f�[g�e����m�73?�G�@f>S�W����u��$U����Q!��z�U����R�a����`ft��e�u)"V.��	ju.���Z����	:�z�M���X�<�5}�]�:w|m�s����)�k!��B�7��6p����Q����<P1pk�&([���	�I�N~�Cv�Hjp[*��N:V`[~[	b)O#�Rq�������^W��K���Ir{`��p9O��v[�l�X��K�)O2������p��t���[	/��+
���O|�o��DW9��&�B�����2Mm�Jw=��i{�Z���y�dA��L�Pw�{;��
�E��"��(t!������z�S*�A�������� ��h���e<dhh�����A���gN�x����H'P��d�'`����#��VE{��(����5�� ����t�{gG���;���;��Z�Z���~������t	�u}�u�&)���[)�^�����r�`�uw��*��2��[�g��jk���Z@�Y�LR7������rJ�;����'��q�����\.M��W���xv�?\m�v[�a )�7��8��r�{�n���F����%��L�Y�R��}�6c$��A���[�����0^��m�A�grK6o�1Q�����az���
���M���vP�?<,D���7�c|�����P�<"
�V�[�8�V�1�����s^�o���9�M��I��r5/�o.�:�#c�kA�D���1<�-�����J�������w�O���:�':���������WWg����Z��K��Ln����"U
���a���;�O��u���M���vy\�����<�</>�!<�0�D��aJX^M ��	X���iV,5�w=��f
��/�(���QR����#��:
��>�s-���t3z�����foPfn�L�a�5���=E�
�]�������`,���q,���/k��=���TT��ww�����t�@5E;p�����Qn��X���s^����$28�?f(���������@�r#tF��xK�(����i�=�2�����"F�04q���
i�1���G��1Y���qR��n��W��w����Z��7@�
UF�����8A]�\���Cd���Z�2�{Q���%�i�^����������,���m�Vi��;��;(�����~"�b^r�u*���������6���)P�����q���Dz(8���V�`x���?�#��)M�9|2*��tn������]�~?/O\�����z��p����ULKk�� o�15J���'3�J&����<q��5S��A/Q��e
��of��(������7W$��]�����cy�/�g%�i��z?8wK	"���j'��}�9�jZ������TZ�Y��N����{5����g
��d69�k�P.�y���;eYu����p���� q���������[Q7�ql�Zv���F���RUB�N�c���X�l��� -���[V��X���3�!k���:���[�����QxK��n2���}��4���`a�a!���rF��FY�9?��QV���t���[-���V�x�G4�|��2��f"���FJ�[�{�������O�l���`�EH��/r���(�
K��A������\	���D��K�J�sqoA8�����8��V�'��u��7�\U�H2E��W��s���L�0���w��"����?u_�
���Q��������C�O��������_���b7'�������$U�`�ND�B�hZ��|���N�a�|�<��;���+!Sn(�fY���XV��|~����mY��sfCm@�f�;C`�s��%o31�������f��L"2A���-��u�sZ������Q�*$�'�Xe�{��w �T~`����4�����E��%h�gU	5��5-B�H��4O�s�Z�9��/5�N���{�LB�l;�6�w�)���
�nr��5�
8]���_����9A�������j�������
���yr�`�ry�\3��8�H��J�t��/�cr��D�<�s�*W���������*2�'��39=��1W�[`����e��vT����������J��
Y�������k'���B�Py[t�p"9�WWT�y�����O]�_���tip@�;�L��5����*1P���\���>'���`�5P��5�:�j<�t@?u"�A{�������k�2���� es/�C}N&,��4�*h��r�w+�`YS:�|���"M�XF�E	�u�1g���/�R�c�1��3��)k56�	y#��ysEhE�V�e��"k��>������E�7*G�
���y���o�e���"Fr����.1��]�c�3�
U�E~��"��8T��7,��lK��{�5�����eAh����*��q�����k��F�%:���p>�0V����l\\�Z-���m����7��7]|��z�������$3����g�\�����K|dF�c�
��/�m���-�����or2U�3H\�+������{��P���C"���e�u��X�Z;�����E�5��.�3I�K��|����N�?���|�����I��D��(��;
�aF�%��^�n���Ysi�f���P���
y-��o��s�w^��#:��io6�{9A�|_+��4�N�e`CM�w��gi���xl�����C�=-��S�6��W���
�`��O!EU\��*�I�%l��"�PbZ&U��8>��,'o���O\$ZQ�>�e~��X
����_����)E9����)���|�b�| ���ue�'3
^y�>��J�Z6�=�����-�J=F���^����7�rd����i��A�xGp��#����HL"Wy\�����)�1�0B�D�+�y���Y���uXD]�E��j�:+'���Eu�����LO�|-Y��5�'�c\��J�o�9�s��;R3:f�,|67���qT�SU������p/wq����NT�4g�������s,_�w3������*;������>����K������U/�y;k}>��J�� ��%k�2����jb���eX����z����Uq�o�y���m���\�R|�G�obsr<������K9
�������
!z��|�uZ��{E��b?��z�7�s�y�:]n��*�);�!z�e��F��0��f�^�h��6�{���\.�Ct���:u�D�:^h�rO���M�-
"4��V��<�Z�=�*�~�����h�(��M����g����&1x�}rTU��o�k��V��8���j�
-�^P'V��P'�dQa�u,�������
�4e��6�Y�>�����F�P*<O�Hp^{�Y�iFE��w�l�[Z�J���> �����k^�`���2;��+N,o�����^��d?���C�We��CUa��\87���d���>�����k�NL�e���a��_���b���A�������I���������i�����t�h^u�p7m��}�Z��.~^�2�y�wc5d,�^N���6�d'|���%{w����I
w2@��^�(�G�L�J�l/>k�<)�N����m��l�E������%�I��� 5a���QKYW�$K-	��8;9d;��4s�!�d�1�Z��N9?��G ���4���e�6ht��q9����i�#����� �����:����~"��e��zH�=-7��o��D������;~f�1���GY���8;�����,�A�Y8�UFq.�.7����b6Q���hJ������Dch�y.�U�B�����+���%��o�c[W��
��*hUo�Az�g�(~�|��I���O�X�7I�oV��I��<$<<oKw��i�b��L�-���E���|Y���n�v��w/w��I#�t�3T>N���z@`����� ��D!RScWv(��1����+�E����z4F��q�q��N���
�:�-�a$V}��"����tyI�Z��]#D�?�����t����� �v
�4B����{��1��S�\!-�>�*h��
�����J,����:��G��������Q�=�e���\/�]]�h#>����;;k%���U���I�+���259���f\�CJ���O�|��W$�fh�k�
������tq��B��*�g~Xo��R��3L(�"�O���5�B�<���ui.A����a��<G����;�0�Q��EGl�r�U}�O�n,>*6��H��A�_��|��~��:�do;�����Qo:��A��!�x�d2J@��`�b��I��?��V����mwD�t�z����,�	5:��g�;�!C�cg�_�����M�����<T���.C2R�4���@���Dx��x�x����]�T �s
���������3N���c�����~P��WH�>�eF��[U�C���&(�<g��R�����h���L��e�����'�>�5�l��S��f�b�3�SS4-��*��sLRq�D����Gu��6��
G<!Z}N��A��093�������tX=V��$�X��c�l�f�t�V��d���B���f��4�<Og�d�O_J;��$�[�fS}@Z-=X����6>����W�9����=�Y�������d
	��c���_3yi���2}I���<O�+��A��
�W��+	D��g�FO��o-������i�xT�Y6{o�BQy�/uG��^���g*]���Z���^��)B������#��1$��Z����o��
���0*&�5�����9��?���H-K��Jh�����-��/���.�����v��%Y�h�l7s�k/v����w�.��`�=<z��gL*dV�ML����6���Fb9���i�I�k���x���D��{����[���'��y�\�����8�2x�Q��f�t**B_�1��%*�jQ��>?��n������ucmeW�(����\��Q���Ua@�Z��>/�;Jkz��i)���o��I�o%[��m/+b`�/#�f��h���Q�G���P�]V��(~mp��w=������V�N��d�5�=$�.>A96���}�um&|)Z����\!����������J��-c����H�8-��bsA[����Z|����F&�J��X�D�TS������a����{�S}�+J�Y?W���o�W*�@:k���5����}P;���"vC^�%L�)?6��$��-a�����U���#���I�T����[<�1�����qu�;�}��w���u=h����C�6�/+�>md�aL�OG���>�����hRI�1�CiK��������4#�d��,��5�QR`��*�KCZ��c�������1��QG���7\.��������c��>��T���7��eN��m^�$=E�0�-�)��1��}K��9t�W�|[I�=��7�,<uC���������c��(:�1l>i�����q���9GI��7d���fNW�-�(�lv�eCjR_	M���Q)3�(��l�V'+��Y��,K����w��W������C����Jc�<+�l�d�l+-<^i�G�GNy%x}�4�qD��g!*��4*�� ��2�6�*�����DS�[��2'z�Yo=������h�\��������3J=�%:��2(�2[��}���UY��R�dNfGe�\�mR-��]���+�cYjR��G�B��V��Y����Z;���
Q
�S������	�������`��P�n��
�"��U�0��v��f}�	�$R����wL����4�G_u��.�����5�m������Z�����5�R���R�<�3��������S��%�l�\|�Z8k���Pr����&�G^7�|������� z�}������}r$���y���y|��F�(���Lt;�|�q�����{@��/?�W9�Sz�`�L���bjV�1�;�[�yU����;!�����y�S�q/��7Rp���7%le0��R^��R��y�
��!�D&+���nJ�G��F�k�Y���]��VA���,[<*��G��B�%���lb��!m^����p�])M��H�Ord��:�G{9o����H�x*���z4T,4D���bY	�
�d9Y�z���*�RAh���9�
�rC��LC=�����h�H"!	l!�K��d���+��X���x�4����=e�����D�h	c	O���P�3Q���j��J�8w?������7(c�s�i��o�>%c	a
/+����d�^Fj�8�\W�t=�I��|Q%VF~��k�g=K����B�������T^������Y�Yu�����b�z�;��2�������������!�V��29��!l�-3F��yG\on��[;y5��������
}�L����<��f�:�WE���8�w����n��`h��%��X�����Sy'*i���[!�yC��m%�d�����vai��@�a|��
�[��l���
���_���n�c�#������Z6�{��'��-�<��Y9���T4�;FY��p(��n��U���pFK����%���l�����.��x;�#&cl���3�����2^��C%�MIz�BD��H�b
d����E��!��TWk/��k���tI�e�!bla��y�o�D��%��Sc��@&CR��`3��-�$��z[����57]��~�|t�k����3�(����K������<{x�6��U��JcKe	:X��:vtG�����(O��wc)[��q����Jr>�c�=���������k�e'�0�=����%H�7���m�L��J�#�������ByLC�����T��7�����Ps��"f
�iv���9R�>���kJ�WW���"~�e�]�B�Mh���O����������� ��K�?�2a^�u����G��iBTmI����+����f�����Gp��,��@��6����X�L�{�	W9xez-Ln�tF����R�R}k>B	�}k�D{Q&���^��z���-?���JuX����
�EV��6��O�mUpN�����������C�d�������$b�����.sU��f�,��U�Jc��1,�'���`���*�o�=5�Pn@��;����.Kv\��d��I���]����V�K�=[���^�2��dm�
���e�!}3�eO*�W@��b=�R��iBM���#[�F���`Z>������J�A-���{�ISeV�Ta���=���vr�0��Ug[9��>%����/����!��n��0�R��w(�++���S�TN�*������7c�5�s+3z������a���y��	7v�`��,9��X72�-����PE(�2gU����3&�\�uUD�(�:�t7p��������T��^���v���Zk�M[|J��������Yb22��j������Q+��N�z�p�T�N���p�35K/��.y#2l��lSjiJ��������D�8H�R���-���a����O��(\�\lp{jY*u�w)����Kv��d^���+�|�6;����T�@�*���j�`����+lQ5���E�c��
f���Q���#��xg�E����O��X8����1�_D�$��������y��S�����[��\������b�p�{������5�*����aVJs>��zs/_BQ���X5�����-�Y<��faEZ�Hde%�����:,f�t�l�(4X0�fs�U��A���3_�����[��<�A�~��*Z������!?�q��pqUW:l=d=�
y����E-	T�@U2	9��]�s]R���e�d�gJ���������>��@�4��XN���W;�>c?1��`!����'u��@-�1��Y's��$T�K�{c��W�G
n������r���M����>Y�
��N��t��y�	�q=N_�%�y��K��FTm$At"8�(���-2yK��;!��:����m������	/]�9��q�:i������5�U���gK�������1${/�|�M)~W�
&D;)����B( �PAZ��O�P���B)quIT@:-[��1=�1�����1}���73�|�������s5���s�c�#�(/M��h�=u�Y?�B�`����u�����D]e/��]�&8�e�J��5K0)b8��P��0yU�OMT������������M���X�T�N4iAY�
�~��s�3�q;�j� �?�Lp��Y���\��t	s� �V�Oq�T�a����$���B�J�S�N���W\��d���������f=����;c(��h�(�}N���b��aQC]�����">���'��x�n~p"2����R�
���KD�,��xaAA�
p��,��N���f�u��d&���k4��k�5�4��nC���'7&��K�������Q&e4,a������6��|��� T�����\Gx������&�����^\����*�~��
&���fM���Va4�p%<�82��[
���*H�]3�;�sL��t���F�����^P~����z������1���s��c��������2p�\�/�n�b�����(��(4�5�������#/3.�"����Ik���&�$0�jpDH�e�;�Y����"�FqM1k��S=���J�^��f�q3"[��o����3��"vw�����A�W�K���W��aOs2�Kz%T���"n��g	���Y�ca!�����'��k�D(4a��K.�������;�����[�'��c��%D�m�$�����
��Vc8��0�kP>D/:O��,J�I��I���Z<�#?���i��Q;���I._�,�&u]HX��d���5M38y�.H-�"T����6EP�������-I�~�Pd,;��`�	;�?�pb��d�+1HQ��fI�'����C�|��~�W���������	8�6$.
���`���bw��.��l����O�%����oJ��]f��5���=��DF��
:�lI�"�Z^�
rfv����qo�=;���i9��N�/�=��D^��(&��Q��Z*������R�{����}������d��1EA�h/
����~�]�1�e��eD���(.��������Z��}'R���5���]k�����U���9��<|D�d��E���l�����<m��*4�6)��t���>��-9�N��5���W1�����-:5��.��mq��i\
bbo9��Vyr�2�*+����'��P��b0�E�'�ICIM���#V
8*�v j��F��e�4Z%a5Y l��.����12�M������r^W��6���f���q'/I�����Xl�Rb��\��=���PS�4�E>K�����XYI��u��&��X Y]*��� �.kq�NQ���(;/�G���HD�N9��(mY��!��N�b���4\	u����|/�'�d�#l��p�y����[��/��q�)�g��v��]��S�������k�����������f( ���%��	�����P�W�����������K��|�=	����FE��l����/�bv��u>��c�0����,��`���le��fb�F�<����t�n�1��b�s4�PEI���"�C�%ml��z�U�`��7�@�������a)i�e�������>'`�������{o����>��6d���.+n���\�=��h�33��\�L:��=���"v�c���n�t���n��%T���7�����<�Tyl��kR�U�GR�H�����D�opp�������<P�Y�O��?��c����~��R��4�%�H{m�!�CZ���t"�*'{y7�3;=��S�Y�I�?H�[���2��f[1��4E��<L@��%�B��Sz1|1J��y�:����*�(:�����%��F>�����3�����U'0�P��t�or|�}��g�B�x��T�Oj�Q�;�\�S8Xm�g�����/�uv|��{<<f������D0:�<7��P�f��f����I}�����|�����"�w=�-Q,��������|���|N����v>�z��46���hD�������tCuK�:�/���b���P��GA��q�o�\]�U�g�1�a��ZX���������ttO���E��a?�X��b\O��?����R����
[����P��L%wy�M��w��
=�6�����0��\��^�8V��a�����}������-���\��5Jt.UX�$�1�W����j�#���������%<�%�"�k��'��5��]�XW�p��	=<���~)b��`����cr5<2�jk����w���b�%�'�S���RB�G*�a�Z:�|qir���OHY�i�|
n�'{4�=��xP�)6����J�rb�����H����X~3N	��0-y�\��H=/@�f���%�R&�����m�������2����HJ������m��O
�b	lr�������0%��q^�yzH��3ik��q@��v+��/�g��;d�	���6��z$#Q,i�[&.�q�Us?q�.+�B?��*��j�AZ8��2
�[O������c���=!*]����Ak�B���:����4y���U���,\}����e�:;�<�Q�$J0�JGe;�"�U���.�?r��sd�2dBMF�Xg������y��v]4W~9���X��a;���,�g?b�!��H ��]��T^S�P���(�2����6|��{���yry�8��Ls;yk[�����(�P����`������6U�K&h���`��S�?U�0��l3�(��cg�I�*�\4E1Z�?j��`t�������R�A����<����2��B�O6���/��MX�p/��JuG}a�@y�SQ������S�"���A��s�ge����Vq������s�l�3>���GL�����I$� �!��F&��u�g�PL�����ra����$��
Nt��Y��:�r�9�m0�P�c5q��Zi3�K����Lx�`V�uy�[v�s�|'� 4		�W����V�Rr�L`��Z?(S]M�t8] ���Y�}����W}�C��
�6�hX�:T����������i�q�W�6�1�n�U�3f/����zl����z�`L6�n%S)�����������6e�;���UM���m	�)gI
��pq'V�%��s�_MM��PD1���	kg;�����w2�fh�V��
��]��
M��^��(�0�
Q����%�W��������u��f��Z,8/fK!�Ki�u��tD�,^�Y1fR�*K�-[(�S���B���V6e�x�����.�&��y�����E[���8*2�r�LS����7^���}z��e��������o�^���#���K�W��M���{����n��&�ZT��M�QG���8S�6(�]T�,Q������U�q1���GPRq��8S�$�R/��S�����f��8}�uj����e~���P!�#�����N[����:���=��1a�V o�X�}b'&uat�e!���6���Tc��
���HD5u�7��������A� �����RO]��4Y�B|(��D�\gU��K?|�R������ �u�����"|�� H^�"��m��������z�vQ��Z����>Ua�F� ��M+e7y�q������	R������geJ��i��T�����|�[vC�e�tn�N?{ K��7Ef�(��[�3����m����mV6*u)���,�rA6�1��s��5@�J���s�A6+����=WIt��$&��y��HF��b���������������x-[��n��������*%m]����HwC�]���6Q.D�����"�y8H����+������G6 ��k�re����}�jH5��$2�.�	v�����{�
�"�:��"�qH�4H2�
��Y��b������D��R�	P=Xb��Yg>H'�{^APd0d$��O)�����|+,q��5r�pZ����p���	�2^��^�9�A��d� -��IiV���u���x��bL�8�Q����>
�^f+2!��#}���f�g/6�\s�����Q2�Q�����V��?cR0.�e�*n:��Xk����y�|�2��x	K��\<��.��
��.��n-��}q�\�f �����8�]/f=U	6����Rgug[�����p���\�4f����0N�K<LW6��F��"�3�R�l�r�����*�(�_�Z��yh����TK%�6]�q���� ��~����y$Z�P�j\;
GP��{�5A=�WZw��L7z�}g�w���N���y\��Q�D���}�l%/|n_�"������sB�6HV��~������k�N�=�v�[��k�Z��`�P)A)�������wR	�SC	2H��FVs�J���iSx�s��]qOdX�� ��FRi�b_)��h�RO�g��`S�}/y���+���7J�/�aTUf��xg�;&����P��Ks'�������c~!M�m�)����� �)�\��q*�/�)�WWi|��u�L�G9On���IiE��p	�'s~�g��$r���\$�R��/����*�9��T�����.�����>����{����]h��������[�����Z�n�^�,��h�����f'�f�j��(�qkCa��~z�R���yIw��eJfJW+@N�&�����!V��r����{�G~�0{U���k�I�O���Ka���\�;�����a|U7���"��\8�!��i��!�8
J��+���t=�����k*���N%�\kb���4�V����_eG8�����R�L
��
y��������
&!,�Y�������Q���O��&��#g#��"������9�n�qR�^�m�k���N;��~��jl�_��*���\��m�D��d��<��h���ql�_A}E��C4}�4���$��
���"��������{�n?S��N<����Fg� ������:$�b8X�E�8�fF��[(�u������l���9��\��	bgX�A�!e%?��]�D������h$��v�2�^�����|^�p���F�!nS��g���/�8����Z�a�-Y�Jo�&����:4�0��R���IF?�����s>E���{l����L�����>1����O�c1�x�	��T{|�3[h���=\����������1w�tpF�;��BV~��������7bh%�E�����P��
�g �P�>e�CF�������I_�k2]
'�%&��~+�M�GCld�m�n��'���z�D6p��Ur�.[�M9�b�3�v�4�����&�[�!N���/��Q�u��s�����n�}l�Dr��U:3r�0� ��M
_�{C�Q���(�Ja�,$��������V;�\M���N��=/�5��%�������s�6sa��d4��I��%�R�!��V[6�+}�AAQ-q��h�E
���vq4��F�Gr[�:*�	At59*�Y�1.�>�M���3	&��+�lb��1h0u B�0��+"�\�N���e��{�*1���!J�2�Q�����7��g���|�-�st��9�EY���"��~q5����O�A��i��,���Q6��\���2,c���"��3lq��NQ.i�2��}W��r�$�b����Wp���W�E�#;O����5AP�@a��%�A�N������:gNq�_�?'g�*�/��Y/l�����YF���o��K�$G��a���q���r[����������^S��F��r��f�f{����*�OK�)�	���o/���c�5_5�5��#=�:����-l3�0���q^���*a��Q|95����^�Sr��"n�,���9�{8�����L;���^w���^F��%���Y���,������p��QJi��'Ey����tL��{����c&#4m���1���6�����!LV�8_l���p�����FF`� -G�T��ah��`�c(�r���F��-S��$*���P�����1�V��#	d�S�|�����?nn	��|g��5*r��_J��C���Q����)Uq�S������p������^��o�x���e�~�sp)d@�I!"�I�v��tL�����N�"25��SGF����e�������+	���C�1l>,��F�m��YG�d����{�`���(�yE|,���R���2��"�
��6��
Ma:n=�'W�����0�6��b��p{�
�S|�����[�xN��"6`6\p���p6�/�C|��~,Rc������0�������?�gp��D�c�3q.�B��>\W��������������^�_��N�
^?��&���h��z��������"�����l|X.���q�t��D&�j����t7�&���zf�E�}X�����>3����kx��1Dk��U��S7�(���h���������C���X#q}r���t�(4����D�|��H��[�.���i�n���g���}b/T�0�q �4L
�`�����3E�A��7�a�H�gJK�:�tF�1��s�����6��r��[�sM��Ck4���#��'~�p0U��W"|��S���"d����������W��X�V��dh;�����������>v���Am
�I&k'�,�/�#iT��g����z5���=h@�]���������_<FV��u������z�e���2��U��"�n���F;}��N���3��B/~����vOrGw��6�}�p�T��U����P�L���H}Nm��dJ��Ir.�oy�w�n.$���&X�\�w�N`Q���b~�cAX�r/��r��l��b$��1k8t"��N�9�Kt���_,�?��������n�]���#�.Zj�7�Fq_�`����������������rTKA����A��>������b����8���k�DX
��tX�e��p��T�k�3�\���K�a�)�T�"�
$����gtF��){�I4��B��@)����H���^��&��k�3�a�,M<���1�+����o|�Xf��#�����t�	`��s����F�vkC<�������_)��aP���%�;�����,u��m�K
'i��Kj��a{{�d������HI�.���?��������Fs���P�v`���jD#eN���0������0����e�6y\o�_���X����0�}�^�������L�D��a���ZE�	c�������:��x��fL��Q�jRYO}����k�s5���������G,���*��&�~rc�C�K��T�3�"��6xM�\���p����lsh�R�����-F5����"��'�7%4#���W(�j\,N��/����AWl����<�����C!W���M0COSK4!\f���gEm-V�Y��a*n��<���,��3gK(�E@�-�lg�'	=���
���9)���T��2C�R��I��+9�!rR���85�~�(?����+�����%�Bm^cb,��B�8/��<=���qd�R#J��cL�����$���\����{=�&i�����p��O0�o��ye��Bs���>`���3`������j��������G�\�\�c�����^��W�X}f60��U����z�b��zJ�Q$,K<kB:�k
_	0nyRJ��g� 0��yM��so �z�/M_jX���/��@�;�����=�����������6��:������>V����kmL��B�;M�H��K359�y7rEn��5~7bk=�Q�)�������*��fI�-�fO��H^����Sr<@�0��8|K�st{-���Zx�^n������/D�)���Bl��pA��_���"lj��Al������a�t1�������3G�r�	�� �r�h������*H�U'B���F�q���`���)+��^I�/��� 59{�,-�r�
�$c�:����*o�	��u��+.>�����Y��q8�P3qa�=!m�A�Z��{.F~;�H�'|p��J�g8��������jm��If��2q6
.�Q1��I\5Sf������Q������.��g��l�>S���5���4����w5�����BL��F��1n��r1Q�����.��]V
�[��	�T/��=5&,����u���8g�� 0<]�&���s�z����8��PC�
�E[a�����o�x�����x�B�����!q��f�r��
o�/�W��3[��p�&���9��k��fd�y[��d�����._.|oLx�;K�5g]F�|+��c���O�Xo�Y\$���@#���Y�p�p+�rD�:k���N��ql���qx[Vj�\��@U?^�����K�"��������dO�l��9�~�d���l��sLW�i���E�[�ekLC�l���n��BA?�~�Su��D���Bm��p1X�����?��[6�s�z����.
�EXSk�_��S<dd-�2��ck���3J.1�$��H7|�-��Eq�\$���B�	K�j�r,��c��rQ\_���@T�]������Go]�.H���THP��+!���a���9T-0&�rh/yw�P?�4����Ea����/������E�fR�-���@�����j�r>(��Z�_?��^�\�����$1���%�0�U�����i�/�C�Bn���Y�\$k!G
���l�� j�\�r�2�����Eu������RrZ�/{�����Fp�Pq���ia��gW�/�[�`���������|"��F�����(s�`�d���{em����4{�������m�atr�Y�K&�nS��=j�,����!�7��������>`��w+sn�8C���dg#��Q���%��'|��w�K��6}��da�)�<��^JQ�i�m������
��S��R7�;��2��#�H��������{s��]\=G�����2�k�J>��x>�]P���V���9���Z�FY��r�&�Cq���M���IM������O�d��I��~s�7��b�^-`x�W����3�������^�B�=�dF$��X�=�����">�Kv�c�"
5(��8����+=~#Qbu�H�����BbF��fc6<�2���~�r���lH��h��������2b3��1N!��e-{�I3�b��e]�j�pIV����������s<��#��`����*���H���+����Q"�z�)�:�!�~n2��(�X�Kx XU�=�����TK�������x-s�yr��� �Tj�74���C:�a������7a���dq?,���b*��n?���#lC9Z��7�Z���P����������7������#M1��k�����s{�=s|(�2�c�M��[�z�B�wo�4�AFM J��t4q���Q*
}�&��B��:��]�$7�c�_6s������"'z�t�2���75�I-� ��������1��E��p�P
���"�[Ouu����8��<R�9��(>04&V>
uk��eH��3r��
�-�yT�A��fC��n��M��M����j�^�\�%��������B�������Iy�H!"k[7�b-��~\�����3�x7�!j<�JnQ��n�`tJM�~�����./K�����\�N�N�YK�zES�=�Cc�Ra^������a�1�������B%J���;HzkB����!���}y�\j���S��S~]�z
�C�]��]�&6E��Z�e���4��c��z5Ke��N��^ztL�6�c�w��4�	���]@h�<�"���s^�z��*7���
�p�.1	�c
^��9MO����+k�3_�Ja�0��������*ppG�H���X���C�]��7g}e�|�4��EW��X�u�/3�����P8������]@%]7�����}����H�z�H����������21�$���o��p1X-�&X7Tm�L�$?�R��^�����_�L���:��;��l����Q��H0�F��)/$D�-3���3�!�Z���AL���B!Ph�l��hL-���p��%����G�����^�d^��V�]�'GX�2��i.�9��}�j��
0����N\�K�T���#�=6�L�&�������W'��@�#L�\�[qK�8���������&�D���.������1iT��]K���.s6ON��:�e�@O�`��maL
�p��*����x9P�@+�!l~H��:��~���Uw]�Y�?1�sd-]8kjD������v�7|�?Ru"��pz�BV�y1+`L���4���{�R���`���`���A]�I]P�����d�f`e�#(fW����9�|uh��&)���J^&����"c��bb������<R6Jj�z\�Q/���������}"~(�B��4N"�������f+�9�|�U�9B]�;j��)�Yg��������U���w�� ���z�G����O���������Fqr��B4}�G]n8�\ ��G�}1���`��`�|��aH�d�%���~#��|!Ao�?�u_��[������b��r>D$yu����>k��5E�������������(����&[!����8�F����r��>����A��������������T��w��0(�v����A:%!�X�$E����\�����
dkl+�~��LrS��^**U$�^��.�^M~���;����@��`D!�B��E�U�b�#'Y�d$�W�%R1bH68?��
���I���p.���.��N7�K��c�����Y���KU�M;TfK�����O�}����/A�-2�^�Ml
�+	\�� ���$0���$>���0i�M�-/����&��
r�	`+-:X2�2��:��2TD���c
����>��NO%2d4�r!��A��3���L�r�^���	��`��1�V!�b�Dv�tS9�{<`H���M�>����OT�c��^j�03�>PfmMi<�|��@�>i�&��������e(�RT����#�������K�:�)wRu�<��V����m����d0�6tM����L�&!���{��di���,��\0t���G%]7[�$&�
�>:SS�UC�r
&u�r��%���,��/�������|`����\�3�]����d��8�
;R^[��,��n�p��d*4$o���n�����8��>P���*By �|�N�X��BY<|"����v���o��n��G��G��"�������u���ZUPu��8�Lm.��p
6�8:Ytu��B0������lC��Z�\��W6*�jD��3�����t5
���k�B$���s]�T����+E_Mi{A�I��{eC���c�4�l�-UX��������__nV��0���&[��@"W�p���8�.��������A��^7����F{�y*������:��D�?P�7��~N)9n������rQ��La�
��;���m���&��e	���Nf-�g�e����e2!��h���nabl��|���gO�������@~��<l3�<�'����R0��.��5G�)p)����8���#+���iH�������\'��&���Bg�&B��� ���A���������,�tTh����}"/(�i^����p�7�\b�Cq!���!C��jo<���>6��������z0��K��\�5*�z�.��%���?�/��
<|q�kQ��I;R9���RU�>�'v2�}eL�e_K*����Y6,(/�{��]/3�i���q&����H.��'u��l�`<�,��T����,��$Me�]��(*��1�c~�.�B�"�3S�,a���9_u�C*�]�V�AE�(���P���;�xuCF����
op��-���$*k{�H�.��>w�H��3����J�O�=W������(v��IU�	��v�6��j
,��a�u��~�!nN�� ��M��|{��y����00fM+���^%�Bh)%����z�G�����^�Q��f�Sm7k;]V{+F�����\ 4�����S��7������4��S���k_���(�v��Dl�x��`�( *R��/^8[�>@TRz��?�c�4}J�W5#O�Bt�:��-AP}J1�&�r��:���ef��]&�A�	�f���9L�b�k��1������wR�x����eu����d��W���1��osQ0�B}>�g���6���Xz4���:����1������c"9��L��Z�b5�������o8�LG6���2��{9�C�2p8
[2��'�!�Y���U�N�� �B<�^!
����f�j����"��b.L� ���������xdx�b5<.�U��{1�%P�&j�'Ki�^���m^�;����y[&�����:��{��*&��
U>���G���������x��f_#|���g}?
��f@b����	B-7F�>l�}��6b��J_�t��|��l���`��|���0�!��ku;�Z�p&��
s��?bY��J�������������rP����Xoc�"Lw��O-��^hj[�flP0�O��r�:7�r�@hWfR�"��X5E�7f��`��jl�{��������$d_��z�E�y��3�m�5��I���a>0+3�| (`�;$�-h<>(�fD��3���RA���1�s4Timv���n��>Pp�����<�m^M�F�Q��l���F��E%���>i���3��9����^�a�)���8�����(6'%K�t.������=�pZ�`�	�\�OQec����L�tq���o<�HF�o������|��$0c2}`�i�E�7Yq�^S��^?�2Il�Z�����6J6��|���9\�d��Kw��_��a�l'��(���	���u���!���^@���6J�����iS�V
1�a��@���`��RK��q����~@!�%F��`��B4}�`��p|�m���0���"�Y���:��������Su��z�����,�	�sX���h���Az�I������8�cX�]^�Qo���NR]m�!�Z	�s���Q��Pj���3`b�����AER�[ C���v�[�
5v�7�G��$r3��Q��g{��y������L.�if.DrDG���LM��x�l�F��z�L4O+���b>�K4��:���:s4D�%F��N�H�CIviM]
�k�*���L�F���y_��4���2
�{y��O��,%�c��7��DDI�2R�&b�8 r�v�����TJ6�����5�����DX.9J>�m�&��� �C�v;����a����oixs!���,<%Y�6�l����6��R|�
I!6�F�X� |�[�$r�Q�T�Am�X���R9V��Z��%R��L�"D��wW,�w���a|�iJ�f�Sm��%;.^�e�eOMLC�b>Q�V�g�E.\F�O��)�K�-a����^o��f_=�9��I��$� �Q��i�*��g���6���3<(S�����Y"%��V5�H=�L�=��.�@m
/���t��W�e���L���g�~:/�m�*��W��j�`;
�zO����!
it\RP����s1�e�u���������Q5QG���T���~�T���+��%2���p���������a&������,�~�fH�A��&��Ad��%��u�l��|��46�_(�&�T7^	7��6`�vL7���2T�����|�M�lN�����?�k��Lf�
�����Ay���]���sR,����
�("���V��o-�m}�r������v��+%�M�M.NWm�/z��8�\-x����)�$�EZ�y�Fy��M�hXM�V�
e&O���kc8�t�c���Q]��x��#&M���y07�/s{;��Ll:�f�����������]��a�(Z�
��v��Z3�L�C�nKK�����<�i��;�ErQ��0��\��E.�9g�}�V��a���DX��^�.��E�F1��E�0�SK�cl��]�� ��6;���xR%����������w�e����l�-�>
��X���������)��qc��+�
]�r6�
L�
�b.D�(��{:)�J/-a�����&���p[N'�ZF�y�*
����W�
�jm���{�F�
�%�A=f"t��H+3�H$V�����+f��N�"2,����;����;`C���!�fB0�[�F��>	"J�N�P�S�/Q��%��B�#LQ�_��:v���{6
�UC��}9jf��-qa�9Z�
����r���6����x�	�*��`;.����L��]=��8G|$��<W��o��|S�V�����s�q�'�qeQ.�f_��8/��<=���n=A����Hhp�\�a�U��H�Mi�/��}0�u�� ��u��T�9g4�$���Uf���V=e���<$)��RE�����=��B��}���i=)6$.�D����q�\�����Q�!zx�i5�d�����~0��!�8�����������B@~`������e^Dpvu�_��_��__��6t?��z���z��/�kw��a�������O������
��O/�;^w}{�����W����k`a���uY��$�uG�^���#K�1�{.wu����^�_/N�[��u�w��o������4'����|��O�fIF�y�����GC����_�|�s����5���+�X��^PJ�����"|����l���m�+�����������7�~��bk�s����I�n��K���+��\+�v=��N�����K�����f��������k���
�H����m^�Lg�>���\���>�����������+��?��y�}������������\�'~?�Y@XH~��,cx���z����]^	���x��]re��\�c����!���R���}y�/��#F�����9�������x�c�'��>�.��Zd�����V�����Cn�.[?m�����\��@���y����0����"F��7��}��x�S�T?(�U��w�����������������1J!�lT�q������W�^��~������������������7/�nn�\�_/^]��~s�_^�
����LF����C�n���~��������?�?��__�^�H��)���1�]�7�\��x��x�P������;�'�]]�/�9������{p�?��:�+^����/(A��J������$���W�^�^*�q���N\|����[��?+(��HD�\{���(*�fsX�P���[(|�m��29���x��fX��2:A��s.%�^0���� p+����7b���P��g�P���6J�O�t���-��������K��\�7��F�r�����?�m����S.�v�e���s��~�J��x��
8v��N�B�3z�L�o�x����u�F��CQ�B8	"������BA��Dh�o��Az�0�(���/�Q��2��*j"���MI��pK\<��I��^u���_u�p�/���h0J[����p)>�(��*F�9�[Rp[��`���6b/(��i��@�39��O�/^eNyx7�$��Q^6��oo��yw��2�d��'����g.���XM5��}��-��p��Sw)�]F�x��}y��5m��L�'/I`������>�5����.�ark����w��*�]���]���}��V��/���fhV���wW����x�z����6�V��W/__��m��^^�����W^����u�����4��
>/����������x��3%����a��F������|��O�����wY�~���,�r�knvq�3a�����~#����=��V��`}D���I�������0w��>������6(3�it����`�[x��H����40���"	����c��t��q-:~�����:��p����??��{�����y�ew-����W�X��M�Z�C����P�*�O;������Sv�Q�������s��"���<�p+�O��l��6�k��&]/��u��%���9����6��N���^������x�������;���&^v(����{��Hf����I��R��PW�������~����0;����x���
��������me^��uji��`��2��z��^��a��:�>��^	�k�W�=m�l����u�����m������>���	K��R��9Y�W����t��5;����Z�C���:���6����h�������|�xP�Qj	He��#8_'�4W��x�K[�0�T�E�Ox��C���NB��&��(v�e��>*0���h��<���?!	B�1����R��9������O	
<�7���8h��v��9�
����Jp���vY&Hn��1y�5K�L�����Q����������<����=Y[��r�,���y
�g�<m�m�8|�����@��������;�v0e�%��:S�����|6�S2��a��4���;�f���N�F�lG���7!P9'����>>���L�|�?���J?�u���r��X�j
��*�Ao~�K���6w�� e�N�W!(i�X�m��P}J7E\Ue��|(����H���_{��1�TpRt��(-,ro*�����]�m��A���m?��!p���E����i��+������ ���	�y���T���LO���5�L�����}��U1�!��K����gp��N�v��G���	��4����(��H������u��9�tw}[$���oh9�g�p���p�b��.��rv�u��b�p����Gb���TQ�x��9����_��&��9Q@2&���2�1�<���=��m���j��3O��[���Wz�L�F^���H]H�&����;&eT(@��j��p���\�N�x�L?��VuE}2���2L9��� ����^[�03�w�@�]!U���+�5!{V	���n��|y�\�Q
��p#�C$.4���0IIm�	$���������W,5�w�k������}R%x����>���~�����z��lJ��K��'[9V�B�T�}���(]�VAwPZ7m�3���Ne�p,O��d�9
����f^�<�:���1�H�	�R�
xcQ�F��U��W��n��l���(�)��f�D�_����8��^A�?}\F���M�������"�{�[����s�����qA���b��?MS(��lP�����"������������	PP����<�|�>w 9)^���x��"R���NG8ahUW�>O#	y�E�I�H�>������n�q��yD���?
���@���OQ��aJ�2����x���_q����b�%�O��	or���+�1i�ME����r[P.�+�r�#}�2����}	��4�)��
���� ��g�Yi�����Jh����8������s}�������I��j`e��� E	��b�h7�6��C�����%�������I��"��"�H)���1f�Z�W���Kf�P���5�Iu�A7��By����;:�j\�n�Z$�����EV��1�����u]�*���5�-���k��8����� �����}�M����8�Y�E��#��3.�X4S8��:*��;,�YLp��'��i�Jrc�������!w�sd��[���� ��`��	��G�@Q��+��}���������Ge�k��r��M��t���]�]�;���f��W��$�D���(�����#��\V��>�H5����t�����y�}����0+��w�0	A9���<2P�Q��j�&���e��?JgI�6��K;���p2������z���;�?Lc}�-���px����x<�/C���� 7����*�{08q^��d�;��n��d��s�>MC��6?�;FI3Dedz=��0?@�����)�
FT|���$s�!�	MUi�w��X��P��y����C���k��������������B�9�������E��3q�!4�3p������%���!X��mm������������Y"Tq�������$���'�T�p~q|���y�S�a+��z��-����k�A��Q���Y�9Y^�M�	Awy�M)D!�JB�?�H\lM;���,��f"�4��u+V���f^	�<��U^ ���������F��8U��Dj�G�n_��x�g�7�
p��e��4e3����V��tP�5�r	}cq�R��w��>N{�$h_`Q���,#*{��.Y|����������Ma�`�g���f����Y��l��9�8���=R�{�r<e��?����8Y��{���$�
������L�m/�q�����N���t�}��f����)���'��������n���'��B��z���sM@*�m#�����7�u�+G���_a���a��k���L��SU�����3�������'������	?��������;��J����o}���w��G�N�C@�bPSa��(�P*AF�q��$����4��e2I�}��b`?gq�;�������y��#��]^LS�\�Vg�E2L*�d$�X�&%d����B�� �l�pu�-N	�/���_/Xg�������0$�����i�����aR#D��_���w����*u��A_o�?�?�����w��J�N����&�fxwY��:��:�A.�L-,�_��y�,NO���]y��H���%Z����Yz��o�!�>weGJBp���c�0�&<���������L�,["��D9�g��O����"X�������k� i��~J���0gx�+�&�1\]4p^�>�.S�p�f�������3rH��P�s<T�9�{�&EW����a���>��k���0#$�Yu��N\��L��0��JS�>��"����c��vZJ������~�����Q�98�A�	����h��zL���+���^!���Y/����_F$?��������y��8?�1�uH2�JW*J����?0���[4�Q&9����~�u��yHk�d������5%3�ZqA^�r�C�T�<���~�|,$�����OE�8N2��3�>�o�k8�?u�@*h�7���0Ok*
��lJ+9��"��=f���t�����(?�����W�R�m5��T=A�o$1�tkx)'b�*�%,���e������A�.����F;G��|�S����.?^X�J��C��cx:�=�.����S��	2g�F���E#��bE���2fp���A\l��t���jy����2��
�������>��!,HOs\;�������
zc#O���0��X�u;�f�*u�n��?9��yw�	�;r���n��%	�[:���&�d�AA"1!g�T!�,�uM��mhs��g�^m���<_�Pw����;H��#t�a+Jc9h3*?�����X�t��q��K�k<��,�������"c����%��\�_6C5��@��O��-<��y;q��.�@QB��x)j������y��6�����������V��r|�C[�oC?�$�����/+b �[#'���O}FN.�����������l��F�Wv�V�����]�Zw��e�n�9/��U��xnN���X��.V�0��|��K��m�}��qA��Gq��
���?�m�+�����(I����(	v�����T��������@����"��q�?����p�f���+�@�hewX��(�w�B�+4T�U�X��7|�WO{�+~�j�:����91�����n�b�������s8�8|����u��,B���2�`��O���t��EU���NB�}��%��5��B�N��}���6�h��O�G����Q����_C�	pZ���c�Nr>!N���O!8�����]�
x����E���
���r��bM�Q�A{�T0�[p�)�mV����;�!w��9�H�]6r��`x��d���7z��f�ah����EA
,�bA���/���z�]f�����s��B��u�����������U��t�7� ������.��[��(�)�pS���S��,l_O�H�fyo�W�9�Q���f��:�7���!.�T�/%��\cW�������k"������(���� 3`B"��O��z1�$!����s�!�N���1(��\�x(�l��� �m��^�w��gD�5�W�F��3�)�sl����V�����\�E6�{�>��������J]q	9�J�D�K��L������q�!5�j���AJ�
$�"b+�XS�t���k����3���j�t���\��m+q����3%X�[���3Ve�Ss���9���|���"�l��O�t�L�*
}�8�[��R@H?�A������ �D�?;_�6���p���~}��eT��l��DzjY�u����$����q�ZE�q�Zw��<C����$�;r2~����G��i�[��Z���&�G��D��!����@��3!E�"�����qt���:��b�g�v�j0O�����]
��WCy�B���%q��!�X��	}���J�8N�Q}���(�s������?�b�Q���lX�M�{��������o�l�\k$
t�?��^"F���	�+���,��� �]�TCC�����^����~���5[�F��G�AH�:F�}R�TBX�`�s�9K����t�VA�
!Ntz�T}ik������y�7�%���d_H!������c��#��Sc�qY�����	��������T`���n�<(��m�/X�I�����P�MN��M�b��f���Z�������8���Qmd�z��|���=��'m��������5�R	�W�/
����!Ppiu>�s`��P=�g�t�=8�<�fE�V��3���/�'4��zE�Hh��lL��������:*P�����%v��������i��r�����*��,k�"�>��0%�A����Y�aL�z��)FkhY�&40,�;��}�M�K�K��ztC^�����H��4Y���?��Dp�u�������fp��Cb�K�#|���%�=_��wp�S:j�N�r�E9�u�������BM7<1�nnmzq��Ehk�pF�A�< '�r��T�}��r�Nx���FV��\��F�*��e.��p���iN�%8�c�
�}�2,���W`8�<,2�������YH-��������T����J�Y��u�'�pG�c,�,$Isd�a���T�W��;��	�r�J����I�jt�RD��B�<��2����e�D�����b�o3����������S�z1���7���LM����p����������������}f��i����!�X,Q������Ni��I�������i��H�#e��X[�;����F�PZ������i�]��(�H�/)0����+a[�f5��^_��W�W�$�����O����,�{��m"��L�H~D�����5�+�c�� �R��^�q�n���P�pVQ��-.�&	������
+!��D�!�+.���������4R�����?���ju�������k]*W��92�2H��`��.����JE����2������*c�}i���(��oe�kXd�#_V�{�)���M�'�|_i��{G���Aq����L�$�7J"@ �Z:�9�&t9������bbX����+���;�f(:�][��
luX��X�9��	���Q&��j�M ������bPpy1�S�����h����,����N�2�S�{�E��L�~���W?������c�~	���c;����"<����-N��#��%�sU�#M�E	���'ol��D�nd�^����J����4&DP���\��!��Nv'&b���%��aw��j��H����P���u�5,�,���I��MK,��~��HI=����Q��R	��	k���<�h�yt����tn__*sHWh8�8�<Zt���=�y�@'�:T:��O�����0����?��l���#7G��P
�o�R,�eg�j�vQRp���� �l6�d��'`�`�Ax2%�[��a���M�=��MR������#�[����kh	�h�v������x��p�����!�����T�N�����
<��K���^�|`N�����&@����'7�w��q����qb�}�����>�N;hg�Q��w�}S��S��d7�o�Zg!(6E���%�}?i��1o!���g�9,�����,wM��q1�<����6����Ec��j�De�1��A�����g3U'��Z%�Ap���U���:���'��m�h��<�
1{�`������q"��`����<�7HR�`S���
����RF����Y3�7��S�|�Rg��a8��4En��Y@�{���9�g_�7F�*�������?=0����f�����U#���~�2�������;D�C�Tv��b��%���V���f��K��7)���x��z�t��V���:�4�?VC���#��M��BMq��^��P�|L��OQ|�~�r���]�I�P��"����$xY�VED�k8�^Qf����X?N��p`I�9�i(�F&V���I�<J2W$����$K��#�([���/L�.s����v~�j����f���{$m�j�b�0����5�1%���>h����`��~��&��y�Y���t�4�o�����F!���i���>���F�d�=���VY��-��.�$��I\�[�L�L�@Xx�O�C��4����rpU.?�4����Y!�W������U�c7>��2'�a�
�������
����=)G��k�W�����<����)�j��6�d��F�Gy�����#�5�Cn��������+,Y,4.d���N|�_�Y��=�<!�`p��s�f����]�Q^%8Gh_�&�JR*=����nC^yea�	��<�E��h�h�d;4A�X�P4!�]�<
g��R�A6�~�xc�c�L�pU��qN��e�j9��?������G2RD���wGb�!�xR���`�!�%�<"�w�D3E�G%.��M����\�@��D�����Q�^�P{�����Fxi��{TL0����%9i��E�D�f��CC0�wh�q|��s��&]�
���z��U�tXY�������W�z������@�<yV�7W������y��^���oJj�J����'���y�<�3[�u��]`�5k)����C]�O�����e��$a���k�z���6��m��(,GR:�<�$����0�T�0mX�����A�=/b��D4>-���	�:(�!Z3��%��.P�U�\5���)}-q���
���R��;��<��Ukn�{$����������8�ipZ���&���4h�*���l>i+�T��O�b�����r�G��S�em�B�}i^ e����8dy=eUt|8�cR?�t����$�b�4��JT���?�	��.��cA"-�LCHC�"��/������
�B4�(�'�h��C�U��L�PpKcg�L!HqXFT���8;�"�&��b��GK^�h�Y[��F�pBS.H����`e"�~"v��L_M���a�4ZL��X���#�7X���?v� �����G���?�"���K�n�d�����z�e��q�:�d�>OO����#�#VAUYh�s&�g(�^6����1�ac�r7&���)5N�iG�c�B�Se�t��<�������X~>MZ��a�HI�JLE%F=�0�g�����I��&�.�?L��q�q�����rV�&������*R����<*U�C��tq.�
dBG�$�����.���m��j_1��( �&���<e���?��)u�����8��O@��+��z�s6�p�Po��.R�/�����^T`A6h��@D�����<������jx�-�K���Rq+c�yB�(K&���uM��LJB� m��b�.�:��X*�'���o��%�FYE�E}P��2�v�
h�py�%B�9us��!4��5��Y���b��������}��u�O�mJQ0��w3�=�gi��Q�4OT�g��
Rq����?����`�`��D>V�����Q2�����eo���,��u�PZ�����M�6�;.��E|:$�Xn��2G�d:Gb��20h8��b�BO�����8Q�t�.����6*���,j'�_F�R�g���T%������ ��p�X�G&�����Y�[P-�N��F�Xi#�������.3��Ey�C�K��8�/\ulo��R���(��jaC[zt'��8b���}������p��Q$�H���0���}�^���������E3����a��,qj���47�A����������1_r=W����K+g8���|�&E|��[Qw(JT�.A���f��g�Y���U��M���\LF��]��@���x�&:��t�B���I����t�q�X�(M3	�����4-|�?�y1���l�CSV�g��=s��!�k�@^�bS���������D�t�����(�H��4����c���
�c��p��8�`Y��W�a�5C�4��vu��ShB�n�6�p��s�:�E�>�R�wC0?ue}�}.��(���F�[u(q	+���^.	�5�M��!�����+0��a�;��]�#�;�N��v{��
]������nD�F��M���a6�r�2�����F99��m�:w\��Fo����`�PI��S*8E�:=�+��n���L���}�=��d�B�bwf�t1VY�E`����ONl@3���+�Q������/n�A��4�;���V��
���$��2&*����?:�����#�9�������<	2A���{����C�j��:b�1��`=�6��'�F�
#y�!,�����S��6�H�G{bG���H�;?����Uq����h���g�wr�8K��!����E�|L\�Q.�S��v�����D�o�dD�����a�Pg����]r��cE��zs���;;���B��
��
9����j���t��@'��t(�g�:���m��sG�['Ge�����5�u?�r@�=��u��\��[�P�-���5��>�Q�����Ez�'�k�Q��m���3i���k�����}x�D���m���P+��jQW5-|S���+C�U%j��dUS�m}��|��5v5���4#��(O�<|,e(�f�m��$���,�����z��oz����w�:������K��t���o�$���J�0F5�(|'o�j������t}���=����M�v�|!��'=�1�v���$�'�/Jz7L�@�����s���l�ftu�Q��6X�SM[�~��S�K����������%�*@N��8�-!����	n�|y���_�\��U�A�_-�j��e�vHm������.
�U�ePRb6XZJ������>������W�b�b�?x��4S����&�N�� C����"�,x���n������O��H�z������&��%NN!�I��w�w�/�o_v���F�f	��j���d�f��)|���	5�!v��9wC?�)��v�l���GJ���a��i�J���R�Y��oz�}�{,8���1�����wE��wu��D���Mq�*B��0���*b!0�\F���/<�-�+lW��R���������6���>tW8���Ox������N#���L�m������u���=������nyh��
o1�Jd^��n�]@�nU`��djKwA�&��%.{r	y�O�����{�%T��4�"�f��A�xL�/US�,����E���]�W��Kv���}���&�Lg��"]}�@
������%���7�-�_���C0QO����JR+U���~��� ������f0H8ws�:��:SU��`���e��4>t
i�����G�on9���V9������1���]��1W��b�2#������N�M���UT��(��:W�H�X��V�K~Z��[V�v��Jf����X/��{,N���p�y&7G/�}�o*�b!X�3�9�I�����Vd�s_�V�����<�E�c3C�m���.s+�QW��S<uyZ���$.��T
�4�Z!�q���Q@i�)�M��:r��,���F0@�(��1I����XA'�C� o��b�Y���=5���#������`��1)f+�Ad�K�/��U%O����I��H�S�J�����*���{�(�1+I�z{��e3��h�0�>�U��Y���J�P���P1c![I\��A��-���F�T����%}�}�_V��\Q�o����n`����T�+����
`>��d,����d������ ����-G2���-y��ER��(��Go�}IU=Hzu\���E)������"�q.*�~|����p����g�OG����.*�r���}`�5��������aE�dV���o�w>��3�Ed3����[�&�W�Mv:��[�����ver3�	�<L���>�K����L��^�LL.����{���M������,���Ws�~>�]R��7�V�vm���z���B��d�O�t��"�����9<�N<k�o���Z�}�
1���R�wa��<#��e����W�gQ��������cQ����L���2e���.�`�7?���,{�����u"�g����rc�lh�
�:�gvM�����G�P�
o���Oe�& C��E.�\U--(J���LW�����S�J��7;4���*����)������ey�_@����<o#7%�&��x���`����e��B���z�iX���a,��$�}��f�s8)Q��+S�$]����w�<�o�����'��[v������������
�������[��r�qS����������<�sS�_�6A�I���J>���uu�����Q]U�����g��%�Mw�c���3KSn��n�[�wq
�f�9g�����S{S����YQ��k����Q<�@��yQ^(�^����=i%����
�����FU[��=�?C�^T�w���h������E�$�>���,�D���;���oJ��P�o�)�X/!�~UC�o-p7���%k3�f?������NDm��W���Y�Df�����v@�)9�1� �Bi�$�t@R�B�F/�l;���AZ������v���gOV���6��OF��S���hnN"�������gm<��hT��7qqx������V�����)_�sZ������6�wy��>M#
��E����q���]��Y ��Urp���,X�oG�~���y0��4e��N�����9���P�-y�@D�v���k�k���T0}����"E,\(����=�����%��`G�X8<�����TxW&tX���JK#

�b�-?���
���I�c�S��t���=��]������aT��5b���A�&auXn8XMp>�R���������%
I�E���$����:.�i��mw��TR�������r�c�1��50�V����{��2F5��&�������L��w��3l^TW~���������*Op�}����A�����8@�}+%�*�}�B�[�A�g{���O
��t��o�UmZ�rT-��u��u`�!�K$d����h;����$����(����}�fi@�X����E.O��[P���j��u��9���?�:�:��o�ml��uY"a&�v�p��w[AOE����kfw�����#���}�"f��Y�����2��)�6�<<��{���3Bj.���w	L.�>n�*eN��
"�K�`����x{��3���X���{�X�6�s!U&��n�f6����U����fPX+M�E`K��������]���$��N��qD��*�o����vhn�e�Jf�5�jFB=����<��`�A�Ti*,V�in���s[��*�(��a�����x��}1��YA��q�^)\����1�jZ� ��a�o4���6�-�4���)�e8�k�gV2:U��'
�Sb�_����C�f\�����8�=TV�EEyhC4��M4��V_������{<c�<�_T&e�!��/���;��rv���/_J����@������M� ���_�]U&������-�%�gW��U���n�W�����C�!��q�<��>���'�
��~y�X��<q8����>�?���&35Ren��;/|���*A �u�2��8��U��	���y1��D��d�*���V��&M�2��HC�|�����)H�^���H�R�;�q<8����ua�;d0[���c����L3�#����7y���W=>�z�O�Gj^�+l�G��r���2]�	����gQ��������9��p������K�j�|<���!�������U� �u.1��5u
�X�F�h"����O2���"�0,u�e�Iy�'���w�i���F����K�m�����������h���W^�	����j<pk0�XYk?���|a���
;Q]t-C�
c�~����[7���d�*�J�f�:d��S"9p{kcr c��6���l*H�,Y[g(Y�]^!a�j�<,���U�o2f����?�kC�au�����}%h��X�kg�����]�u�vZ�*�M����b���i�A�����
�I9&��G�0T���o�u#�o+G�H�R��)	p2�n�N���\!����Up�O�|*Av[�sI{;y��M,�����I���+D���y��~N;j�W����e�M����V!��_9`P?���9��0���vn����]�U�q�K�!O3k��)�)Z�q�T��4I��X�����wTM�����-&8���������'��)��]{���Wp�E��XEY�X16����y��{s��b�=�_�4U�b��
��A���<�7eX"R+�i��x����Ab�+������C��I�����6�w�
{8������������8�����U���=p���FM��7������U���NFM�}ke��>�"�;.��j�_VT�,wu��4�N���>%�
����O�)1�uk�c��4���p������SE����N!���B5=�����C������7j��o�Q��<i3�
Aq>���y>ykPy���x�(T  7�?����K&�����I�_�����MTzC�=�!}'�Q�1��`V���E�X��*�������q������c�9�9���~��P�O�Z��N>�n,wU���<�@�d�.\'�Z�3CVd}�i�F�����iS�Jyv:�~�/����'�rx)B�'h��@p�2���aQ����X�/���V��X��q[~��C?���X���<
_�g4K�&��r���C����[Q1,5�2��P'%��q�g�%ARyh`_��S�"�p�����2z��0Z��h������&q%����(��Z_x!@h����3��8-Z�NY#P"
wxk_dX�ue5Y[�QV �����	/��B�����oD���fZ���i�E����gm���������D��6�n��1����/C���il�4�r��Z�m���NU���������sP��%,�g����j~��w�7��qu���o��a?�W��*�e�9�?����0����2Q���XE�
�:m���c`�*4���u���80�-4�!����Y6��;�����?8?������L�}U�"��y���g�y�}�u��l1&��E��xM�uS����@:�AG�*��(�0k.��#2(��q���s�9S�c���l-B�r���������l6�q?6Ua����S=�����,vq� "o]BA�
�]W9������
J'2W �� �����"�gyi����-f�?����:����Br6�'�+���,��CJ�� 	�/H����G���GT��~��{��(.Un �~��?��X�����m��S��R�0������7�m|*/�}h-���_u)��N�������]�nx���01Jp���w�A'��{�����"����T/S�$y:^M��;���e�7�+�7@��{������b���L��2��4P�R�;#j��?��)h�U�����w�}:�u��6P�j�0ma��R1�RxZ<s���rU���������i��b'~���*���i�k.e�K��T4��iU�u�{U�)����M����p��//���J��}�2C�ri���-o��G���^���V3T�i���\Z��p�!��[�[�!24��_b�Y��������zJRq�{�C�/}&�*4!a��V�|6��.=$��
��y�0���5�T�w�&k��K���[��1���V�+�������dN��
V����aS��("+��T����7I|\�����
���V�!�H@�Nf�f����
�A3"N���M�w��<�K�V�v���>�N�q�l-9���	����w�f�MV��T���������{���+X0����j��w�wf�|/d>���Df����P��2�����T/j�y�d�ZB�_��rL�,�����w�L�K8����<����A��K�����j�5C�?X������{��Yq��F�OM��J�-cq#�{�|�����b}���ot�uC�����P�z�:��}��)�PQ���h��Q����0��r��B�UL�-��V�)Q��K��Z��c�Q��V�X,t{��G`���
c�=7���i)�X���nyq�]��FVN��o7�XM}��1��Y����L�.Y��3"��
���?�2�B�`u[��X�T��� ��OX�~�������v� '�ez��<���w098X�B&����W1�����V���L���^=����jl�_wJh6)Bm3���d'�@����$_�����5��W�gnqd�2��a������^
8�������F8��	� �
����"�;Ay�+.�s���u�q�C���D~[5v^$&J���1%��Z5z�.���yeV%�!��m<F���H+���g�������b�M�E��x��[*B��(�]�Z�h����(�������F&�V�U�n�_���pv�M��'��*�v�+�V�����C���u�)&��[(7��Z)��
�
e<��d�0���&RN-�<$V��2
��ssO�g3/l=2m��������O�~�?������#6���'�z��[@�/ Z����/coN��R���h����\�r�w�B�S��~�j�r`Dm#�n,]D:�E$�!V'�D�qX�~3~S1�`�$�_*T1b���in��j`
k����JJ5p�Ve^bq��������@dm���Q_!�!��H�5�	@�S���1b�x�a�
����
�N���jsM���6Q�r��yn�^�\���U�S8�%f;(D��,X�P��B|�\�`����ONpb�������[[�+X5,�
��3+W�P�M��(*�\%�]�aK�i������B�BV���xc���$�g�8���;��E0��2��,P��]�c$wa�g�+1wM��uT�7���2=V��S)� ��f��D��zQ����_���x��c�e���B���j�V!�WG���;������t�s����h
��@����>O�d����j[�D\����0TM�.�������7E���{&#N��L*u6��h�.L��=�I^M2���~�Q��
��|1��Q�aT�3���u�;�/����UEUC�����x� �b��
K
����`c O��&�x�������i�V�A����73�����V*��<�y�������-������^�q7����y
��/e�/��6�������fjI
��Q��@7����}Z'��O��3��%��m����>� �We����${��*����K���~����dm�\�v�424� ��r~oA��GX�F�9���h���j�$���J�-��tG�N7#b%��Y��t���6e4'S���]�������"�������b����Y?�����Q���|J��)��Y�tr�-#���Za�s������U�����5��������_:��]P���J�	�7n!
�hV�T�i	#��q�!�CT �zj�������9{@��K6��kC=�}4'��2�D]�����Y�y�>��$����+,���C�9^�@�� .�c�{��y��z��/�������;�G�`�u7m�K���������;@�=��������v������*b|�q�p�{B��+.����{W����F�r�����V����Y�cla�����U��4U�����+,��P�SnL��|���5�����]v�(����[R��YM����B�T]�����FM�����{����Gz���y��z��\�\��vAc�K�[�+(O�n.T�K>C.�}���v���r���A�Ng�[��
��L{n2���9B������8�PI
o^+�_�7��lY�P>t�Y���&��!}J�C�.$-���7I�o�c�g��g�[E��}G�5�O�8Y����9m��X����@����#~9KV�6h�W����G�Yl����|�(������7�U��Y�� �����_y����P��?}EX����(�<�7��3�����2�~��`Yq�e��6�}����O�(�����a1t[�
�}��:�Q��=�,�r�f�1��g~)��B��0o�S��S������>�9pD0�AA|ixA��Q�����+TA��3�A��|Fz>;_�Jy��*���6%�xU�]AT'`-vQ@��Q�������TG}����.�l�����'(�j�y[]�������ZP���59�]��y��eJ����=������W���/�������b��h3_�����|���������cM��/H��f�H��MU�����"���Zw0��f����X�jN�9�r-���p:6���ll��F��9sD�c�s�)ig��'C-4f�*g��������9o���L����7h����=��28�����A5R*�@�����`*���>����*��U���7-]+�YR�������C0`t������!�%N���Ri�*.�Xx�u�$N�i<�o�g�0Hd�En�`��
��b��A��-��^�y�i]��<�ko�~�����d0����90��a�d-�j������+������CDY|�4d��N)�GD1�N�p@_���
/����I"�(m�Rw7w��f'F�C�zEE��T��C�T���*.��U�B@����!�!��D��L9gi�bN��z�����>�M7��=P{Z���2������9���g�j�7t��7(����b�%ST*�0��QzrT����Y�����Fpis���oi�X����6�d��\�u
mz��� e������Wn� -�fB73��F����G�����xl��Q���C��`��������a��
��D'�pv���
�$�tHo��e1eL��������R�6��&P�Xu�e�*FK>b�3J���3����d�K�%�H�/�����R�c�W���������)�+vp�,��0q��Y9���v�� ����
��pdpb��i|w]�%P�����9���[�P	����Be6%�4-i��+A[���7��q0[.Ws�7l�ml��t���&�4�������
��m5��r�@5�GC��c����PB�6*s^��+��_�� =r�S��PQS�rE�X��r�����
=�S2]�L*��Y?����SP+�����g���`H���S���+��J�L��%������0�!��
���XV��Z���
�IC�.cw8��yfhU���x�/=��\��"h�J�O�g�y�>�G��?$��J<������GW7�B����`����S,���q����:L�p7���.+�j���m�r�$����+����]�ATcS�\���'�{�jCq�%�{�+���y���u4�;W��9���_5Z1�;��L:f�n3t�^�d���H]��|���KV��0OW^��Lt��{����yE@���'�w��+�?e�����e �,���h�c��E�����?<z���D�����~�
�?�[���I;V��(���-�&|�����6W@b
:M�����s(�=��wa�����}�<n9����M�6�:r�����@����X
k����e�f����.�����9�]r�������E���M��������<��[���y���#�|f��T����/-1�X��Z��
squY��x]Cg��n����9��ho1�k�n���T,(���<��X����]p;�]���r��<��l��TlX��j��9p~(s�#''�n�����
��UVWj�a�MT��Y7���;7U��t�~�'�?�E���=�F��6��vX���4������p��T�d4�8�4�ZAyta���c�����	�����v]����9&�U�M�YpxLp�>�������+��N����%���kl�R��sv��qK��D�n�p-j"�������v$�(���5��a��ke�aaMl*C��yu�� ����J���k�U��4����Q���^�@CB�P�$�-�8�b��N[�Y%c�����b�#W�a
B
�43��Qy�S�W�8���?Dk�������x��hLa�"��dT[::�+g�2#�:���A{0�;����/�1��
1�k��NuR��[���}���J��
����gc��f�k��s���S�?�37J��#ff�^[��T����S�eN�� �F�A�@�:lF�_��u_�0�@#c���Ue(~m*M���F�����_�	;�,�J���d���%j�y�����z�cu�g����eb�e7e��;4����%n���a����V9��8x��_�����K=� 1{�]Z,��3v��W�'��q���B���0v�9K�"��q�q�+��'����G�$X����[�(� Y2~���I����4�'9)���e���=���NRVQ�/�����zo� J��C�z7��a�p����>��X�u�D@�x �+��� R����"x��"�QU��fP����Sp��l��4O�;p������:%�.�E����@dF�h����_�)&&`��S�����	��$����iZ�e���e�`�
��9S�1y�V�
H�B3ty�m.m�B�8��t�r��ZT�.I[���ib���%y8i�\d�������?P���| {��15��r��&���AP�����P�o�a� �0�l�!���������~���*��:g'����(����|��-vAfu%c����u�PP��R@T����v3�~�u�v��x~'��=��N�/���P����\������m��V.2�8j�������Z�j��]T�CAy�ZZ�l
�{o����G�i�&�����3�sm���<��ps3�V5��*s��Y��N|��Z�v"�Gf`U/��Kjg��I}������(��5�*L+�I�4���T6h`������/�+���N����\��M�L������a���N�*�[X�V^�~w�c�u8��D��H
������3�������t���m+��t �lKc���)|�W�:.R#l6)�c{���
~�������\�a�5����K�����T��y��?�e9���f�@&�i^�r��mt�-o�|G���`:sF-+���>�`�y��e�}x&�"a!ZVF���,�����q���E�GZL�w�!T7Y�,W�-1lH�I��{(+S}d���r�iL�M`s,j,�����*��a������U�[n����x���=�QZ���8�	�]$��YTtQ���(�2�&�?���_~��R�En=/Ka�$TG5�>��>#J-�VEC�p�$Y[�2�l�W]����g%�E��q�F\'��"���?&1u�6wM�=�R�M�j��A�7�Y�]y.������6���!Qo����[��/�&�q+�=�lqe���CM������@y�<,�G�vU���;�r���c�.qR��k^'�����N�����\[�.j��,O1-�"�o<t���)������,���D �|����Y&�PF��a���K6����#�&kk���Py8s�������K}�Q�d�8��2��w5w
t�#G�Q ���B��	`)�����dG���r��E��x������P�\_�?�x�����K"�q������>K��-mX��"���������h���@^���:����|<��g�^���H��e�����U��
5�8q�E��8`H�����u��P�~�!��jj|Xop�0Fy�V���C.�X�V�Ec�5H~���'��T_m���"��}0�oep��i��������!E��&�[MR�`�god�]:�E��A�O����0�<y�%h��E�$�{�tu�E�'���t��\B������L�@d�H�t,\Q][����i���?�sV���P�?���
�����Z�Xv�a�6r�L~���{)BU@�7��l�H�o6S��:���9�����q���E�����h{�g��l�Y�:�n�p@����:��h�@'��y�/����������]<:��#������~��-�,�0��W����QH8���>"�R	X}�-�M�����`����fE��)�_0
��}A���@��$���%^�$��G\��U��c��H��U��r��/��������C��	��<�*�xU�GT,��9�C�f�d�,Q_�{����|����� �*���E���+L��^�����K�hm���h4�)����R���g�q��r���I���D�Y��u�j�������%7i������A{�/3{�_��^�R���
t(�"�h������C���]�A����p��s���k_�=�D���i���YW7�x���*O�!I��Q����}M�o������0B����|�_�q����w\DMW�.	�xz"��z�����;P��g��������c�(�(������:FH=No(6s�l���$��<��2����z*,Fw�����Z�p�h�"�� gHDi���i�I��^�<��4�VF'�L7������m�l*a��gh�1���JOxw�V<��&�ALFV4��|�i�zU�N����O�e{�dJ��OU�<mr8��|�GE�� �}��+���g��j�H�Q�B�9m���m'���?�X�9��F��N2�(�&����K��1WN�=N�����$1
~����b�����j��x.EE�2�$#)��`ch�~4�9u4T����]0��w
&�D����U2���WI�"_����P"3Xo���w�f��"���Ap(�/�p��.H#�<�!ii�&H���9F.gd�T���������y�*5&���y��������~���d�7B��
C������4����Y��/C���DSaC~"�2`[����Q�����_}�HB��V�I��Q�R�*q++>6>�f�q75�	}g<�����Uy;��k	�\�$u"YO�6�K&v&d
a�������������P�cT�%x�M}��v�i�|x6���n��Y�=2��A/L:I,�/����S:d��M��x��q�w�a��}���!�`4�����a��?��':�����D8�zB��1���Y�Eh��UP��xOO�K���%�+�#�Y;@�][�<�.�%�����3dzcI(�L~��1S*���*or��r6q9�������F��g�����Q?�O���0y[K}j���:l��s|�%$���<������0X����'sm���D=���h�t �9�p��� ����k���A��+i�\���� "�2�1g4�a��#��`s4%D��o�.����S)WB�-�q�V� R�"5I&�"y����Az��J���/�x}+���?�4�<��qFU��&r�B��u�.L���)����������[%��L��g�#�X���1P>��K�T`k{�g;�s�;�pW�g}��/����C:9l�`��`�4L��t��o���'��<�������F�?k�l?�������+���
8� ���s="��wKL�	+�5��\3&���������VGd��(�>&y.���uyr����if��8�7w�P�k�}�����>zT����w�{Z��x�*2/�n�4�%B
}�74\��%�1N�<���A3��
�*L��:�U�a��o`��!H�_%�#�"���2���;��fb�S���������'���eH*fg�� ��uTV���Y��~d�6��F����_z,� qNZ;����0.87RM���T���$����E�����-8��k0������0�����U?
���e�nGLN9���N�d��(��@�ed$���I���D��D,��6��	�y����M�<�NUs��dVSk6�~����� ���P����G�*�T@f�11a:"���8�c+g}�IsP|�9���`�DF�U��r�����-���]�SmL
dh��9H���HE_�����M��=q��������
k3I����<�����"9��iH��}�9G2�I��lT��U�����J���e��2���k�����&�a|)&���4~`N;���>�E�
H�9���
�A�
���o�U��%`SA�1��2�%���pe��'o���TuI�����d2;R{N�����CJq�����V�7��n�\��{_6�$���F�V��p���a�5�M���x�;�?����g}��Gy;<�D;>p��L��C�O�}�u��|����=9�[�� ��P�o-]��n$ii9mg�n�%�f[T�������R���
�&�O�
8X��Y�C#g)�����,��T������2�E��M���KxSG�e�U�P�c��3��Msq�h�P� P�
�/}�2|�������M�����nq���O1)� ��*V]��x\�D	�/E�T��
���a��&�P�f�F�k��kf��86�[��p�(��j]���
�\E�I��o����>!�vM<�:��Wd8�8s��������&!��u^�3f"��,x��U�0����A�[�2D������3,�`j���%�9j������)�g�iDl�I��A�y�M���J�}�u�gJI�2Y����!��Y���V��TLx�2�F�>�_sk�2���>Dy���8hcI�LL'�i�d��u�9��@	9��)���R.�e��X?�K��V�A��C�
|��RL��4�6`:�g�3���C�~�<V*����X�����q�#y����%�+�N#c��)'C�H�L�2�P&�f
�[NR^b�$�FvT�h*�8�����"MGFE�%O2z!O�O�<]���h����u�����Q��Y�?���Z�\7��������3�L�3K?���GO+R����-o�4����'1��;�9�}Q�z�����HD�8� d���/l%5���K����l�t6.����������"�����FQ}W��3��KV�;F�� )+v�z|�e�,����4*Qb�?}
��:��������+N81��a8L:l��,�,�/~J���f9�����U���l=��1�������CY3�*���KB������7lIX`��
��9��i�G�v=��l:����q�/9�:��
)��z�}�^��6�T���u�C���Y���l����TN�s������'��"�����O����r-���qL���|��������Yf��D;��p�%�����N�P���\�%pxI�t,�/�8������FnI��}�� '��c�3��"b��/f�|�W�������6�)7����x�l|+�l#�G�=v����Ep���hTl�)$Pa���q����t5f��~���6y�m�B��QPs�y�����H��4K���W4$Oz�~&���8:$�����ir�S��<����><�:c��Cj�E��3RT4�������+%D�2D�\�T]W9O�0��A��9�PW��-�L��b��D�
2�\Z��kT�V&���o�$��i�?������9(h@H�U{��D���&@��B�n=�D�M���������$e���"�r�h�p�&�E�V��@_�����]h����4���>}(��2����I����k��j�0���R���TB�(��%�V��]}yO���n�����:�(u
W��/�)IW�XvG
�70WQ���w�L��Sw��!���S��4C�SD4gx����������5��B�����YB/�:��e8t���!�?U�a:AC�������#u*V��j����
N���eN�SA��n�9�=����s����:L��\U��y�_"f}��O�� :�q����ps������2Z�
��H����u�J�����t��V��2�7����m�5;�|����Y���.��b�����-��;$����6z��Ib�f��^�ag��AJ��V�AC�1������N���s�<V@��J(��\����S^i�.�rOr��}�
J�� ��]��z�r��\���V�T�q��U�E�D�������/�6���-}j�)$��o��.��8K�,�#z��sIg����Q��bj_Q�k��U���d�����a�L��q���$=*����(��.+`P���
gN;-$ U"�T��G��;{1&r����*�t�K�w\U�V	T�9�mJuQ�2��R��n��g
C�NYU��D85%)���������U�X����8����Y�L������������x"�C�-'e"����
��MV;E|A�c"b�����\	:�Uv�x|z�nw��&�c{�c|�w���$I`gI�$Y�&X�Cv�\�^���
�Q���:-A��@:���L���Ub�M�@����>�J\���B���>�[���`�W��ZM�j��C��9L�W�`�:7��	�{-T	���A�������EKVj����kA�����eX������ze�B>^��SC&��?8`���Y����,A|�,3r�.�%����������G�	���4�@��s�&+�Z^�_+�����)�5Ek�.��^�IU�~g��a;��$�<�R�T�����U�c�'���>���F:!"U��Q��>��%���GYXV%;��Pht��8�<S�2�3���L
y��?���t#2�J�9	���^���E�r�~W�o�]�������fwx�{1������"$&1�2�>��@wM\��VC�O���I�50����+�����_LMy���W/b�z�K/��p��i��$�-.mA�P~�)K�\���C�%`�0�#��rT�/�����*�6��~��z�2������Z��QP-�>�a�%B-/
(
������Y�e%�A\8�2&����X������XR+�Rm�?�h���V�mQGU�?H�&*]�2���_��gOw�{8;���S�s����t8�X�R�@�@��?�Ol�uj�*��'�i���P�[R�v3I
��b-"\�&�U
�x���44MC%.�=q�Wo�;��o��t���� �a�������SX�F@���8����������y
���q���A���\U�`�M������]�p�������	��
��~v�Ir����h9o�����?=�EE��T��<k���V{��zV8�b��'�i����&v�]e��R�De"N��(I� %HG��'"�IM^�����H�����5/���N�\�o���M��N�z�\D#_J(�Ar!.[�*bB���l��!V~aj#����X���hZal;Y��=��L�}�x��N�}<�$��Uj���������4(��I����,=����Z��v�8h����+B=e�w�8��h�9���h%09@_�����)�f�I=�`�n����Ari�[�h������D"'�5V�D�U
'g��eF�[("BY�M8L��&09��������'��Iz��4�D��:%j,nv�mDW��pAF]6B%C��jD0o�>Pu�z����.r��4�w� �hrGO���p��f��\�)Z��}}������*{0�\���I������Pk;�fx]4	)�`�6�S2�Z������v�=<��'0���E%2��*	ePR��D�87vOFV�2����QV�4"�@������( ��e1���L_90���F�a��e'����.��oEy�}We�I����'$�
,����[j���T�?v;��)K��$�6O�y��WY�c�,P�5w�4pz�5+�I��2�#�kU��Fl-���G�7������2b
�'$v�^�I-������(��6���D�IXg�
� >a����(6���
�)��5�������yeT����X���D�����b��%\^��D#&n[%��6�q���%�&�A�H|0�@����j�o:vHS(������x� K_����'�7��=Ef(��0��7]7��OEu��s}+���!������j�����V�,���k���D4����%��\F�����2��u�-���eD9+:�%fhu���@V� qj��b���b�_��k��)���t[��P@�H��X}dC��������Q%v��E�\�-&�O���]���u),���n�CU8��Q��5��z4���t
�=.��[����D�
?����V�TH���nXj�Awf������+��.6�*��=0�8s���2D�UIM"�B9��?����1yr�wkQ�,�,-S�05���
?�.��L���Xu)a��]gd4���,P,�_�X������������������M���
�D��	E��s0������*����mv�a�'P��a�}*���d����3-�u��k����P����.��T�G�x�`!�C�q#T��ilC�'�u��d�M$G]Q�!"Y��R)��D�m�6��A��o��O�=�6Lb�C�����	�:=�2�W�t[�
C�%��iun�����N����4L�����������%^�kcY\��K���bfj���0��j
-H%{]���1���6�������<;�=�3�D'Iw�W����a�7|4%����[���E���!z��=�_�i���>��
4�� h����f��$b�w�>�J�D�k~�N��D������Lk@C�Z��(>>=<&��cQD�*��
��������_>
m�(hD�uSC�ge�8v��(97;��he`m
���if��;������p�B3+���jM�g������4�G���x.�-GE%V�Px�a+����)sQ};a��L��&h�&��+�:bA��]��0Tf����
	�/%g��`�1�S1c8�yD�"����� ��s�p.�S#���57�f�n�ND��n�TM�.5I�w����D;�(Q�DE?���0�[P�lf�������io�����v�jO]���6�\V@�N�VpK���j������I���_p�mz�L�<�_����b��YFa6�
hT���>�; �5�7��.r��y�������y)��L����Mm���OQ/Xl@V+<�"�1�}�OG#9.��AA�����
�$TCe�jZ<��������6��=�)b���,
h�����_bw3
1�u�D�p� �T��!Ym�\�L��dV�f�����a�XC�+���-���4��;U?�-�h��;M�
��������ub��
'Q�M���$�JM�����F���@��Z������&�����z�<����)�-����Tkx�]��
��7���7���^�8w�����#�.��}A�H�VF���U�*�]!��=L�q��o:%D$�����w�{��S�J��v�� >����/"� ���%�?������%[�ry�r�m��X6���6��?���������1����r�S/���,�,
|-g�?�����%���7����� q<c�r�6���Xh�j1B_�	�H�/�*�yc�x`�W�0��5#�
�+��t�<X�v�W�A=V��_.���H�D�
]�S��h�>��7b.#�0�C�",��{����%Q2�����X���e��@CJ�
��h�
����#Zr`MV�U}����k���r�@������PC��}��A�*u�3Fp���������2���;�nE�T,�JEx�����j� ����v04�#���:����Ny�����A%�j�p@������@�a����%t�}J5s���fNJG��G`h�B{/c�����*��/�G��.<�
w0��1>�c�}�fo�EI���,��V����A�v��a$���us��X�t�\w����-3�@��o#�r�D���[R�W�8�������3�{K��\��"a}�$?���G�����i�J���w��{n
��A���]u	�~:�N�/
5��eX(5�:��Jy���k4�N0��E&s3D�8�3d�Q,��Y�U�F�������h��@����%>�1��
5QV��Xk����-j��+�]Z;�U���#j��hf��HQ�W'��`JT�����J��;ca{�`�|�
�d�\|~z�o7q�|�G���+M�)��S����Y�f<��E�U�~]*��f�tuP���2e�����pG�\���`�<y��al�gl)����Z�D$�\7
�Fz��;��E���K�c��C�J��Z�TO��
b`�p����G��������9��;'��)��.���
���:�DK�!z�mS[M�2o�	q��n�2�����mPG��!��R1�X�L���R��<|�
���sm��u��q�O�f��ir|���������b�qZ�A"�h�v�	M���z6D�%(J�RD��4��zrk�,���4�cFQ�q�1�n����ke�p���	_���
]r<"�
}uf��:T�<��y��Y����O�����e0V��:z��4M�13M�����D�{�`��
��67��^��d�;l6|�c�Fb��D�0�ZK�+!C�p�uE1��P�N�t2ES����UAe]�����D��WY<6�4�"��
�J��%;�=Nv(U+���AF]S!�
�@��M��T)�����"FDT�Yo��c�v��v�����?�Y�x"��7��+�e����!S�	
)�6���:M$�����eu�U��Zt��rI��P�K��=�Bd����DR��h�2��}�Nm
����.><{B{���y���$�s�-�>m=�����DK�^�,�����d������L�����Y��@�d�OG�]��g8����J����R ����_�T4+~4t�_RI��fS(qm��l�:�A������PW�l8x��[��?�fy�������O	O�n8���z
�[����DD��+�:�zQ�m��K��������n�(X?o���:������`�4���|�!���,E�}2?x�!�3�����^v*j�����q'�D����2�C#*)�e)TQ��2�P� ����������]��dI���t7�`$)LN�O[}��F��L#��D�6���@C�Y������������U������z�����e���!��\D8�WFN�t�d�6�Gv�7�.�G����@FB+I=���,��V&q�H�DCfHEk����wd�a
���^����j���P�`Be���em�<+!=���k������NXu�U����pj0���_�'�d[����'���n�hJty�<>�������s�A^�*��Da�'Y��CTq6I,���0���;<������h�2)�P����������������5�+N�X�#�o[�'+4t�v���`�lB�d�y�yBHfX:�V:�D������� e�V����f�����I�}���0�V����.��q�>��a[Z
o��[U��x�	Q���R����fxQ	���US�&�*��l"H��7)cP�a�i���SH*R�-H�mdN�m&$��EE��v���)��P��~��ng-���D�a��i=��r��������+���#�z��0��6Co�*M[�Z%�O��=,T�ff�����e��Uq5��&���<���^��u� ��k��5ZUJ;��rqg8gi�x��Pe^���f��`���YC��J�$8<z!rP:��=F����>�E������'�?�9��^;1��A��<1D�Bs�%C����[��\��I�����|�����4��!�����z�	�����Q�3������^���KT�������p��,�7h���F �_J<��D{8X0W}5A���XC�!�!��$�!�zXH{�0f���X���3W4d.��jt��=�<�J�ReErh���p!����k��K.���2�TD��@��!�*#TD�#E����p
fT[��Jd"�T�j$���%r���K,4({�
K@k~K�K�
��,��h��,�DR��$2����������.�0y��������h��eH�7M?s��@�?�%�j������f���a\����F9�h�g�yK"b����e��pb(B��=�|in)�g�����%��m���P"�C����,����2���'C���{��a�,'�Y_�x�g�%��T��H����1���c�#d�Fp��]tS������ f3(kO#8�."��OP�\�����p�N!��ct��(��?rm����X�
���0x�����l�B4��'
H���4*�m������^���Q��N%|���165}�a���be��u��S���FuU�+q�%<����oy�i"�i���G=9�9������"Ou�&�?���f:��I�d�5l57���/�R�PR�u����� �-���03�Evj�K���r�����$�'����d����@2H7�r����]�cS[$*�z��
��n���@�:7��bhy�a���t=Q��"�?V.<�Y�Mr"�� �^�"RV���zS�T6��v�������Xeg�\G������if�T��y�{J�{�?��Q>�Z��/�r���S��~�EU5(����d�x��V��f�DG�<2T���D�MwqA���Z"")7�Qc55��H-*��#��t��$���
nh��/�6��xq�2��8PE�\DpUE���D{9�7�dJ�s�Q���K�0<����1<����>HhboX$4��{��%����(q�:��[3��x���\��-�*�X�����k�4e����` �K@�����
U�Y	s�,�K��Lr������4�5���e��"�D����E�{Q����$n�P2��*j�iD}����|*�F^J���B�t��T�����u��g����Xh�D/�,	�^�y�W<7�Y1�%����?��J'��o�U��R�4(K����Pq�?>
[����wJ>M�7�\HC(C�h�,F�a��2HKx���Y���������MXpr��$�����M5�������I:��)��5��@����+aD�a���!���4�b���������V
��������Z�����2����s?���)D0��\��un4�6f'I�>�Ehf�!�U�����K������[-trdJ-�$�U.��7h�s@m��q"�����}g��6�x��INV��~>d����5����X��wUoZf�9�/T����Ig�P����uzf@jEF�B��j\�����_)�[��������[y��_����Y�}
����8?����"�����;h�~*e��2���,q�>����f��h�xG��,@������5,y
�?e��A��������dN9�u�a��8@�z���W;`]���Y�������:Lv]�(���2M���u�z�����R����,�0���[������.�4@��u��������$NDp4�{�!@"M�nM1%m�^4���$#�f����d�������@u:"�T]-����4��D�)�"�n�	���T���*��a��n��ktT*��p4�JSHJx o@U7��u�KZ7Y��������Dr�����/N6"���s-��My��3����	��%����DV������ @�*cD �e@���U��r�w3g
s�"}eN3�
8�H���D0K��*�m��mf��nm���@gq@\��4}�[Z;� ����tfn��.T�����i�����L���0�GVK�B2��5;Ft�a�����L���L`��9���P)��SD��uE�Z��#��x�QpMN�T�u�,"��f���s#�X��d�Q_���-<�s��t@Z��'�����:�1�A���L�w��������?}�] ����L�������9@3�s"�W���e��oA���a�4m�W�������q����w?��Dw|x����^�����1]�I���8Z*4��e`x<�x�>�la"N������3"�-����F�S����%���D�4K� �CQ��<m��AD�?�����3�
��L���hh��t��
�)7�p�&���j�u^��H�����P�Ap�����L�%"����&�d`�&��f%"c�7�h�����eLCM����4d��2M����c��p��d�{>>zC��"y�C�J}���%�����1/�`��F����J>|�M^��_��1�E����2��{��n��)`�� �?d������1�^5(����[7�!�����V�[�2���F�-Qc?�_���]m	�:oO�Z� b�c��m$����s��GD0'�4<5��e�H^��(����N��fu�ma�<>��7�Z������a������-m�,O���%	�c*B���N3iVL���"UP:$<�*I5���^&c�����+e�a�T�������"��������9x��r���>Hw�od�t1��u��$k��E��c�u0SU�W�E
~�US}�>�g��":�"�~Y�m8<��aB%�T�GG��+���^��bd�����4�$i2�j�GE���\����^��V������R!��'yT�u�m"���qUJ�����z�E�y��
��i'�
"��9���A="�}J{��8PV�"��D�CX���������j���ny�s��:��l��u�CYY�>'��2�N�6������#����9������_���`���i��i��g��%���'��-��CK��i=�D���������L��<4����G�p#���]t��v�8��������K7�����]{[!-=�"k4n���7M�"���G���W1�.��%����3D����S�&�}�Dw�ML���t��������D���!�����m�}�^�&�6^�B_wV(����O���=�����H)�,s�H��QVq�0UR/
OO��Z�M:�D,K����G=�rF{���[�h�����h��P;����2���������x+l���/O��N�,��;��d�=�_z�����Z�)MY�:����z���C����Oj���W]p8+�v3Q-:D�������8Gl���q���)��<v�����{(SQ|
f����h3��h�m��D�{��24�����[�:��>���k���-q���t�ZpL�����=WMO"����?�9�k�aWYl@��E��QM�t@���������0�\����!9�C{'�Zt��K����)L6���{�A�������1�X"������T@�!����$2h��AI� �<<���n��I��k�����(8 7A���S�W�������nt8
$�����<G��2�O>At�,����F[]N������d4�D���:���������i� #���`@S_jd�q�	��/����
�fQ'��
���e@\."����sjj�Ge��8*p#u�%�5_����"�I��gK ���^�DX�y�<[��@:�"�u@l����HDY������aK�|�f��(X�rD,��������"�p���dt4�n�����_�����5� aZ��hN�4R�K�PW���I�W��c9��'B%Y�M"/�W�H���/sp�	�`����e���$"�(���n�k���^�M�z�wx[��|���?��~�"d!7imX���h����#��J����:������.�@@����� ��5��|��Yw����u#���q�P�7���av�?i*�.����*�d<����3"���4j6�%����`�:HD48�0�e�� ��$�D�Y�5�X����e�:����X��a��+��sd��2J���P�
�)D!�"�P��
�^^���*��:�|P���`��
a�g��,�c�����7gY�d8��`3*rD����x(�Oh�G�k=N[�?S�P"�\�O���b�\���OL�����2B��pZG0��*��d�t�
�� ^&o�0��M^���I��)/`�l��eA.L�Ra�+B��s��W&X4���Z�c8�A�4���.k*��`gq�����h�}j�b�tDF����W"xE�\��k&22i�L���tV��u�:	����^�K��������4�q�!*N&%��������"
k(\���mX��O���������H�s�[�!Y�,�v����1I����+0��\��d��������w��/���{eZ��r�8�������}�o��x[{!���q�y���'s��#�������si�+���F�D{���v�c�������7Q����nh�����W�����~*7wR�^��d�����F"�����Fj�.���a�!*�It�&2T��A����������D���Od��_7=�$���Y�E��%"����Y3�0��"���E6R���(�
�8(�{����U/h��l�����&��J!�z�B�� '�T���T4���

��p@�5��i�LD��g���bN��^�xZ�!y�#}��3Ur"�j�M������5��d,v�4�o��I��u���@��'��/E������--�
J�jeHK���e.���*Vw���P&�_*���s(�����,��X�jz�BEk��\������,v�����2P��3F:�=�4D��������i��)�f/G����$���0<���2	�
��s�(
�X���������(+�'�c��Iz�K��N9�UN�]��2	z3�<�j���8���&�tZ;���a��J�t�t��v�5�%�|���:��q�dF��'��.�����Z�M<m��cr��b#���!���62U����Cx����C����O�&��K����?�0}��DKL�=Z��m���4��NJ{4!���?�t���z�Mz����h��p�����Dx���x����m�y6��h�c�<�C{�'�G4��C��Go{A�M�0����$��M�O��G_�
���|��b��v;���CTCB�NrD��:C����Rc����x\!�m����hO���>=������1|�u;#��O4�;����v� Z<�Y}������\A��`BF24p5�LOKD�eu4�8h�4��p�
�M[���8h��Ph����0tEC��U��;�x��Gi=����;�L���7=R�&��<�Y��YC�[j�aV$�P�9"�h����r7�'&��W^*��������A_�LW|��(��/djK��n�hp�'"�W	���y�qO0��F
�)��������l#�a�H�C�sSc�/����	}&�7Ih8p�>ME�D���uD��m#�6��jD[���':�����FBiX�*a:"�!����3�tm���`����O�*��)0��Q��Y���/:�%m��LY0���w��������]��g9@V�whQV������w/7�����������4�~�]M*
���Z������Y�kM[{��~���� �;���3Z~�^1���@n�������z�)Zh:�Ih��W��'��d��&<��}4����E[�h�!�4�������7��������4n����7|�����y����(ic�����P�V�T�UM
Xxc���:PsR�D��\q��6nJ��"�@��f2S���Cm
CIN����k�?E"�L&�$���$a'��$co���hpi~m����ba9k6Q�z��mNZ�'�|������L
�T���3�B����v�����  �������5&���c���/U1���T �C�#�B[Q�'"
S���Y�Y2dH���*	�g-��c8�����d���d�r!�������������z��ra����"�B�Z����#C"������f�p'��k��z[�3\D,��h�D�H����X���`�yy"�<",|o����Aq��8������c"��	G���<zD����Z��n�=[��#����8h�f/�=[�y�v���O��a�n%;6���=��8��?���?��t�����y��h��Z��3�-����6��O�����[������?���??%���h��W�������-���'o_A�����t���1���G���8����%�/��Hlw{__A��|�g��v��}�o�q��:�$�S�>zDK����61	����$4������q�=G;_q����_*|��h��7�n&3W<�]������
�h�wV=~�0�|����z�j$Z�|�(
=�Q�z\!q�-~�h�a��+$��M��Z�y���J���[�h�'7`*#���$|T�F��M��|K��S_y�D�6��4~������[�h��������i�E5�[u�|��-�w����
�D;�~
��G����>�hc�4���C��c�����x�=<��Z+>�{��h�H�A2��D.��q�G�7�#���Q����[{��(E����^����-L������8 ��80Y�i�b:�H27���n�D��?d�)������e��,��$��8��c���S1A�����#/��f��c���J%��XGjX$�aE�3�6R�����|G�HK��D��j
��a$��53"��l	��-����>�} ����\�:A��3������:��A�w�m�G�xb����<����f��Q�P��x�g�c��r�������h A%d�M/o�`��0*��o���n�L;�iP��3#�D�(Q���5�d*����4(P��^����6�bxE���Wi��-�nnp,i�4���
���+�Q���b��H�9�����9DOSJ-~z>l=�����yZVtCO���q��V�=Z�|<<��}��MVw�����������d18����d�EL2�����+�<��yZ��j&�l2`)�D\�a�e���F�%BP��lf9��1D����o������*����.��QA!���=�0��� ��]���Q��MX@f_%"��H��������U�sqQ�j6"�m��}���u_@8��A���2+��2��xo�.j�s��u<%��go�D�X0����%FZ���U](��'
6��BA��I*����d=�H�~ND,L+����j�7Z6��6:����*n\p��ri��p�A��9e�>��r#<X��n��OMO%�P��@d|�S�*�kpM���<�8HC����������]����#B,[��^�;��7Q�h�=���`��ua�5r�Z�=oD����I���dqXbK(U���iE�(��J�����2��iQ��g!TiJt�=TM����*�%*���]��p�Te�4�{���,e����`�C
���9k�JfrI���D<Tk��W0�d�Z���k=4�<:�m�u�)�[G�/KA^l�J�3���n`����P�c8!��P��=�<��U�w�!�ZG���1��A�D$��{���M-
<P������^���S&����M��:Y-�b��kN?.��b2����]�
xBNW��3ex�j ��V���p�q��c<��uC{~>�D�{.h�����'���'��|�
�1��O���)kOD�����{x4$���&��l��t`�����K�QZx0�Ih���������;��v:$�A���-�$XXhSQ�� :�Nh�1�w����T�!�6����p����#�&�CK�����1����6S��L�L�7%�2P ��"��)�g6+ �.�45���OA)�)3l&�*��0��}��&���
'�	A����J����.S��qe�$��?��t*������S�;"H^�'�k�;z5��
Pe�����s��Lb�V�s�u��+������6QY��x���R����IRq\G[!j�Z:�W���"�&YS����;��S �����wg�F����3ED\c��,^M�}w����������^d�5�g2���El�30<���	g���
s)��k�[��D()��&o�DQ�4�1"��_"i]x��f!<MD����f�8
��nO��)�&)��d�YCs	�uST�
�L����+C+ U�w��A�����c��.�t��y54�9(�c�d���*���#�Y~D�����]�Y�������:���5{����eDL��t�=F>�n��a0��D�����w%".�?t�K������1�BF]Vp C��*T�e�*�JN��qGuN�y�+n^Y��l@2\@D4��q�"���pI���!�X~:-�!���]�N,k���1�j:D����L��ua(Z�L�z���+��f��t��+`p�|Z�@s�?�y��|�, �(��
R���5�4f"T����UT����Z�z�goh8+�I��6(��O���(���@@\�L��h�D������j��"��La�G��$�%OD[�r�X0�Q�u-hu)�XFV������H�'9:��4�*��LD,�����7K��r8]Ss##-������������D@�`�0p�T�"��|Z*�l�MI��Q+��� ��Iq�ikM��e�2�y_� ��]5-�X��&/�"���u:Y��a�4g�w���&��?����aX�#����i�.Ns|"�C`K���}�z���:����A���`��_"�RJO�����xU��Z\DE4)2����8�
p��I�i�BD�x���JS��|�����t�
�3e�p~�����i�3��<c�\��X{a3=@�hL�wLE2w<k�t�� ����b�����jg��,�[��D�d>�O���i��H@�
��[���Q �	g���Yh���[�#Wb+LB/e�/
s�����4����HC\���5oV�����U/�d���&X.�Z&�t8����CF���D+ ����LF����4D�s>��r#G�5�,���	/%�=�*���_q����s������;��U$�L�<Pa�*`��}_6�L�X�nT������:�3'�E�*T���&D�����c���.��)��T�-���e�����W�hJ��'��02X��L���!BN[�8�Y�pt�@y���_�[##����z��������dG�+�w}E��������Yw>����m&�ml�����@&���KVU��{Y�����(��;�~Y�<h�^Q�F
I}��X�A�U�A���d����8}�BzC��Q�������yx�J��� B
��8+�R�`M[}���[<�[�Dq_A �n%aN+�"��U�^�|�$Q��}���D�4#Hx��s0�%���I�db�4�������P��d<V7?���['� {���K�vw��ah�xC���z����uC�X��C�W����=<������6\��|&����{�p�='���h�����9�w�h�����s�O�2r��;
��W��8S����=��v��==$X�/4o��A{��D{�M
ASO�
��z��
,���zo�MU�<m�{���|�Sh�t�o�?��HS���y>�3m���i�u�����f�t��������[���f'k�{xy��+�^7�C.hi���=���=>�7�o���f��F{���M���ah�e3K��=���vh/���h��g�%O7��w��u��
I����!�;��6C��oh{-��9���j�Am�������������%N6��w�!}���Q��v'K=��6CS���t������
����|r�=�������eC4u�]\���v��2mC�K=�^����q�'���1~������l�FS�E�-�K6C�!��&wV�����.y���oH���1�r\���T�D��0�
(�������T��w�74�G�o��oaP���|�f>A=���1>$f����T$.��3��}z��C��3��PT�O�a����6���c�q�?������Hv%�&%�tE� Y��p�n����Md�R��1���E�:��(d�D��;�P�x�:���j�E����R1��`B�QI������&�k�)L�A�)���z��&���Q�)n���}{�?�
�'x_�!��s���Q��y_1)�Y6��H^6�.��E�2������EC]*b"%C�
������1n3�A���#\�$���x9L���n����jAk�����A�]=��<A&�s�i�yx��(M�t�����w!`��	��q��~��-��t��N�EVk4�1FEh-SV����7��)^�2D��'b^��6?��a�F{�{�P�X��v�p���	)��(Z��mr�O#�Y�7�F�Y4���yC�yg'���p�����g�Q���s<���B8�x�)�}��x�f���0
i}O��.?	B?��>M�j� �)�I�j����w%�1R+$�\�1s��ZF2v�A`e�1��f�&���1������!!�/F=5��p�SH0�ws���4��@�2Fc ��s�I���IWb9�gU���8��3��0�"�'@s���O_}B����jWj4�w��
���t�-o�L����������>�uQ��A�l��)nt���b��R���$�������+�_��R�;}-�� �-���?Q75�Zcl0�|$�Y`��8Z�h�nS����;�����GQQem=��L��j���Y�FlDlM�W��P��m���&t8�G}WY=���5��2�����Y�#ZI�0��|E������Ec we�13[�
�����>��H�	�K"�rhY����BG�md�l\�/������w~���p�N32ax �3� 0��]�
����vw�O�x�����I;D�P���*n����epN�]}��+L4O����C��M��6F��Ri_Ph��@r;:_�����D��V�j�%������F���~b��L�
�0�a�a�dd��r��9�z���*�-�� �\S�tUK���`���m�M��txf��$+������h�2����tL����`X�1��>�/��S��������eE��B��*� s���c@�cx�}���C�5s�6��������N����!�0_�l�X�5������@��=��]��!�G�A�9};Y�y6Tzl����&c��K35�x� ��-���on��Q������X��������FV;RP��8��4���He��.���0K����b1�i�9�7a���EE@�v0�'��Y���/K�B{��}�HR���H#`��Gz<��:@i�����=��`�����!�s�+3	��-xP����s1��f�8��<���"gYC�	u����:?�4�M�a ����| �C���S\�(�*R\w!<A����"/����`�%|�A����	����j��r����
&������,��C�G�
<�����������e�(�Hx��C<���b3�{��e���pp�F]��
�����_W��u�mqfx0�M$<(O6������������	�zlM	���������#�k!�����u�.M_�f&�Mg8���!��f�
�2�	�1:D�s������D�V�\Jh�1SdY�\9P�B�{�H���7��Q�b&T\�FU����~�/(��������G�����h��.���u�������3AD�8+D(/��gj�z���z�0�Y�������������t*(~�1x3"���E��X�������!�/92���(.\^T��6�xf"]O��n�,s�o�Fk����y�P���;�H�7�9�����9Y2q������t���D[j<��
&=�AFlLQ������D����w^s�5b\g������S�+F���.���%B�E�BX"��^.��]���l��Q������R<$�=���]����\����8���\����q�)ea��B�d����Fil����g��Qw���[	�p�?F�g����$<�$l��N��f��8t������G3S9V�V,�?�s"�nrb��/$U��Y-Yb�?5H�j8����9Z����*�
y�����\#��#�>�Sf���0��lP�|���R����z[��a�r���Cq�IHS�s]��\/F40�OO��uM�a0����XlG����C�DY%o��pK�[����c�hO��Y����~�/>�~��3��k��P5��9k���aVD+�P�&�����m�ke ��=��$��1)�@�v��w�h]2Jr-��t,JPBF{O��A;�U�^d��I.����|��3)n.fV;�typ@�H�Q�ZX���\���B�����/0@��JT}��}���7m����#������@�#Z���~dV;������p�9��a.���]�j'G��Ap8����nD�rl0��1����?GE4�C4�n0��UK\L".��5�f�-�&�����92����-��*m��L�~�Ee/.L���;���,�`��H������U:�M}t�L=l���^��d������3��S���#�}o������y�L ������0v���%�`C~����g_0^����L���`	��U��J���5����wW adv��}&a���b�������Q�O��.��7���|0�eB[h�P�b@�c��c �6��7� ���������G������x�W������}P����L����Q����;�l$7i�	�������p�@��a����D�H&|��bY2�\���'��L�^��{L4B��D�]
L`����*����'����kS���wYY� L�f��J^�r�%�.V�(�Uqtz�d)���B�,p���H�	�}v��/��f����M�pWl�0����R�r�*�����O������`W����(�L6O���x^v�=�owm�"��c��P����o*
{����!X�4�c�F��>��r���$uc�����M}���O����t�c@��d���g&h��B�4�~|�q�{�{��5���W������s�4ZcX��4�5��Q�����B�SW^����������fC�5�2���t���J�Ec3��y�����Y�_��������px0�9#.�
�<�
B�����L==��B���Y!G���8�0��:}QBN�����[��
[t���B�:�m���
�l4���=�/�����VO�,mY�D���Gc{g��Fk�X?�L4��������by��.������=��c�0���E��e�z-������;u��h�`�L�(��a���z�U��Ep�=�K d��p���Y��U���C�e8�W�v,=��`
//��s2�~���c���]�L�/3c��^�vr�0�g]a\��r2������4'�U�4�T31�$���c.���@���=�*��UqS\,���/A[j\cb��g@����
���*MX��	v���X�����
�rM�E^l�0��S�0\�h�y+LD��@mQ�=�E�� B=��
:����I�\8X�F�zk�44vN�	1�5��C2�zc��ra�.�w������14���0�}�������V�j���
zXHz�T�y>�?���',��'�	xh�nC����
��l�gK3���D�7E�r��>����=<n�����e/�����W�^=A2m�u���DSS�C��7DS���h[����%WO[�7���~S�����w������H��{���L�k�$�ppj<���qV�k1����P��GZ�Ao�.�qA>�HH�@<5T:�+~���6�E��!���������?��������D��S�;-t�d�<�)����Z�����[q:���Tm��0�E�(I��p����c����������2������
{L��9��������y!����I��Bp�DU.��9.�������6��jb���1L��GH����AH-�l����	UT��G�F��>�������1�4=��x0<<4�!Fp��TINn�6nz��75���.7E�MT:�W<�s���u�Z�}���o�������R����d�ko����2rqF�?W�d������ �jJ�wa�F�YGe�u��G6��kpA��C�z�p������H�u�A3��������+���"�=�5�|>84,v��;`���l����=`�$!@q�B%�dQ8�8�'0�]���JeA�mzk���i�S��I��6P3�C`P�#;[c��0Fe������g�#p ��
�j��OU�p8�CR����x����L_vO���2
�/'U�����y(���(f2�2T	�f*�l�nI�JW�A�=S�
�?S��@N���/�A����PP`�8�"1QF���)BU��U��E�	��Y{�po��a��I4����6���L+����~��|A(?���=�Tp(��p+�59�8u�
:/���M��8������"���C�"�O�!���������b�m:@W��K4-E���������X�Fp�<M�i�U:M#��A��a��R���h�������
���txV��P�s�����
��H�2�-�p�3����Z���B&�VOy��'�kA�j$���<P#��0��h7HsA����
���b�����I�
��z@���?�>��&wb��*i�/Y�� T��,3���~�f��y��z�7�����?p����l]!;��L4�E4u�G�����l���T}�;�)�����~Hm�phw,��S�L	�s�F�2�I��A~Vit8���	.An%p0��` r����
���#=D�`�����-<[�w����=��#T��Zi]�Q���O��
}�C�a+(�QP7���(^W�0@�S���(��tV�&l�
�S">�D�hW�om�b��
$��7(EM*�F�-�� ^V>!M\��M�a��9���u�M@G����8��M��(�`���	���I�d|8��
W���f~&�8��n�c�`���U�%��:����7�
��/���1 c���
�
��n�t,n������Fv	�TMb���
QO���*:u�3�G3G�o��%����S���H�&��<�el���
�@��"(�7��Q���k������*+���|.�%@J�
x�Y/�D2�8�Q�Z�X��D@i��I����H	 ���{z�ZsP`����L�_��&��=�����~48��h�� �6 ����C5����=:���0��\�!�v�T�G�Q0TUk��5�h�����!M;���:C�6����8�:7��10��[(��	 !i�����h����i��@����zrrDK��y�>��KE]�o������Pu�P��,���m���E�E9�z}����iXd�m���J����W����>���/n�O�{(^�H������������S����X�	�!?���qyQ�u(d!�k��[��Z�2����h#���0P�nupfJ��"�x@��0��(�BX[z�X>�qv���E������uY�
�Te:�������P����e���
\��h����2{>�����:�8�
�z�r�Ag�U�x~a|/D��.Y=U��n�(>�����:6��zX����5�I
�kw���f0�a�������u������
��X��_O��:��}�����b(#���-5=���d���L}���E��~�\�����W��������������s�n�d������?a�����:���������~��n=��U�K�}��)����2l�^������[}��J�6�{������������q����j��o�P�c��t:��K�������Eu8����_@=���38���?� #�?U�?��I�No����x���/*n�_�O����/�2�lH�qp�b����`���Gmf\C�~�rQ�1��?��N��3.�����c��c�����������'��>d�������p��`���^�[����������������A��7U�e�����na�f�����7_����x����*��U^����<PG1�	���Q��m}i�u08p��$�~�����JC��hF�sd�*�W?c����tD�����9�R�I�{S�~0����4L{`�2���,�0`��'��L�*�UeB��9���|^&b�'u}��} @9j3m����@��$u�b��0�%s'�U����JQ-7��Q�����Y�\A������j��<��E��4�?Ze
�`��}7x���G��b�7���0���.:o*�U	}/'�T�&�6����VW��@.��.����}�m�����92���1�Jpx�Q����	���GH��*E������i���1��YBPH �bF,K�m����;����$m����$�R�������������i����l`"��D�|���a�k�^���!J�0�j���Ra��Ju�$��C��v��a(MSU��^f�:���E�e��i:\�;0�ax��R�XI�Z#8�8����������h��ia.'�9�Ol�W1aP45'�{��P����!-������Cyx�������j��2����ge� 8�RUG`)e��?�xrv���a:a��F��/'nY�� �	��:e��R�e�m\( ���J-~hR$1���+��������7���
�8���>�����W���+x�`M���m��ui<��JP�!�	�[���E�Q��9��	��F����.��(f���<�Q>�N/!@�����+;-�vF��U��(���L0�!�I�L	��0K��
f��<�$2�tp��Z�l=�b�A[�lZ��k������`e���
�C5����t��\��<���P)�=G�0��~��T����S��3�o��@�x{�AM��b")�oo���^�o)������������`�����}XYZ�]�[�(.���E)�w�-a(�B�y�>.-���u�Fe@�p��w�G����j�C�F���?��v/w�������@Z�Q�k��;��k:@y�������>F�e�Q���q34��Y=����^����uYZ��"��y�?�<?��_���^����$:�iB���W��9���Au���Bo6b���5��S6NF�xK�g���q��{K��$�{�	fQ�������{�+�+
�'A@7YOP�A��(��I���t�����8�Y9��KgB]O2��r^�g����8�-���#8���&"$��� j���p\�}�F:��8ud����c�B�w{�?���g$��AN���d��
��9[�;6I���[+����L
uU|��j;���D,�����c[^6G������V����yv�E�X��1p�S=c��a��0�b���x�?�s�z��L��Tz�����L�shQP��/X4��!�M�6�Ap��0���z�^�"��3��D;���?0����G/"����
:B�7��3���r���e�a�U��/��0c�rr���}�G#%$�(�iu1�$8`���{7
d��J@��2Z�P�th[��]���Fv�d���#���3V9��r�\��DX ��n/�Qq[�(�6�d�^��Ou��%	~WTf9��� P� J�
�6��	?E����Q��Px#�v��8��w*C&��M�UFB��5?�)W/Y��������L�j����-�g��P����w�f�UJe�����[&�1���[��X�.��`���bV��	��1�h�d��e��Y��*EL�����^��0>kU����VRgB-��8�D�����H���@&a������EI�m����u�!�����
��4LC/P��`fv���]l<7��s.�
(�'��1��Sb����-j]*L�46���O���Gz<h'{����K��!�0�rl,�%��@�{Eb�~1Q�DS����17��XV�^��H}4:P�j�!�[��8Y!	�����)�\�&������5N���k/,��&�8PLL��k�C`���n��=+�����J��F&�
�`������q��p��@�� H�&$����}H)��&����������CA����"�0���?k:��"C�A���y�Doi�"AT��3*-���?����l��yyg�������h��j���Kd�J&�Q�]h.����0(	W���,�0�H�	��lR�!@k�.T3�����f&�����	�v}y ��4��~���pp0�iH���~T�\�*�	����/U	�ft9��%t�,��e�\:�LW^�>����[+C���|�#�!�a%���Z��|\<��������������������Pz�F��YV���;�Sj��L���������r\�����[q�R~���^� $�����QbY_���������pa�=��&-�[�T������!�?e�����h��������n6�U�	��i(oN�!�z��p�N�Yb�����bN�`���&C��+�w�9��VL��Su�h��3����4�\38u�q����eZ���u2�yB��-��]x8�t��]~��x�
���H�^KE�Yi#.�3������q���*[C�����3�A����N�����t�<@����H����&��z�p��bL�1&>Z�mT��T6fb�s��>�V����R���B�;��8&sc^��C�9��6����D��.�4�9���v%����4���`q�g�:l'�	��.{���j3�iJ��p��eC&�������N&EC�I�r3a�o6�c=�5S����3A.���@�"�Q9��qz�2�L���(#�c�Z�Y��0��!��yW�}�]�kY_6*t������;Q�P[j�4d���4�M��@�������S05a���?�n������_lO��av�1�K�112����x�,&��
:S+&�����xH�E�A�v6b�����b
� H�q[sl�u.N��q�sn
ab�qV|������&�j�.���p7�U�a#����`��h1CQ��e?a�
��~
{�U
���s�`6T	������p��u���.T�>�Bc\+�� ncz�rY�:i)|�q�u2t��\��u�j�J�c�3����Rw����Q�,����[�cb-��y0�*�����-������b]	��i�{�/���aN�86
�P��3�~A��'OH��sj���&�MK���YY�1"�I����M��u�h:x",�Tk<W.������N�c����I�*yd}��W�Hh:�ts�+�
*�T�o
��L�C�>�t�X�������lze���L�^�Q����������G�����R���d�9���W��N^!7���~��������"���C��*�x�@��q~���v��V�$��1�����U�nH�qTu?�$�:u��<��&���1���������=
Z6��8��N�^2��W�
Z����^HL��H��o�����o/��v���
��������������q�`oej>P���UQ
�.��C>��g�����>M��������h�T��>�^�����
_O�o/[����z��>O^�{��}��D������CK=�����(<���?f�=�y\1&�v�W�=z�)��~K��M�4��+�w�:M��9~L��^��}�4��������.��{�-�}uiZ��g6�)~W���s���r}���=+�4j�*f������m�(]�pTS@��!]�������\���S�+�< SM��(���~F��[�*h��\��L����)����0p8p��V+��33s�H�X��L�kyk�i��B���b|ZW�!�J�c��Akx#H
d4O���t���o����9JH��g��J���!k��*R����s�}&�5�����.�CU��N��zhS���O���^��]o��)�[���o_�4����	Y�~}�wn�����c���1�6^x/:����F1B�o����Zgxs�N�PhSZ���r���b�������1�j.!p+]��d�}l�0�X5LC�����+�:���B��<4 �-i�r��'�2�F��PA�c}@L?,����p�x�l�%^'�KHd�-�Z�����"�3�����XH�����#HcN�1�f$p��cq2;������c��
fk\�`6��D���s�����xk6���y�5,���*2h��
�x��J���&�\���)�L�#�?�z��

;�,B+/�l(�H��ak�C��(;�q�&e����K� ����>�!���Ae"}��Ym���Y9H�L4b�c�Yq0
/�N��9I�%�%���$~x�{��
t�}[���zoU�B����W����m������ir�������vh��xK�l���<>���!����2�������$V��7����HI��n�n*��-�?����T����-{J6��Y�owN3}��!Y�oxg�}>�W��%��>[���C��
���|;����l�ny�M�Vh����i�gK������[�{y�%���>�o�l�z�n��w��_a��naC����q�&��y=>-}z���e{��mh����fhj?o`C&���-v������|u!Z���^�x��}����=���������0�9�5-~�������
|�/�t�pB{�=op/\���������!��������������O��w���fo�h����~�=lf���������Q������s���-�=���y�hOO�-���y�IVjD�Q`����e�����h�����"2����jK�����Bzo��k�l�Q�����@�
��+��n�,}������^�z���������M�=e�&�4����!��������@&i�Z.�����b3���w.��x7�B��b��(����XD��o��TT��I�U�:�������y�`��~��Q��H��]|�L%�;��T��9
�j"|8�.�j����Aq��IxXXL7Z�E��TuW�Xg�@EvI�X�&z�C�.��FxH�|�j��o�S�����C�q��(���%�D:��~5��E����t'� f���j��a��z`�va�3���4��m��?E]��(��S����b&@���Eo��T�H��DF���'��.����4�7�AQu{y�s8�4�0	���&,hz;�d'k07��Qt�iN�!0�]lj}��Ho�nM��uewP.�X�G>3�`XSd��C��1�TLs&a�Wf�[����BF�	���9��F2���%��O_b���\S�y~
(�F�B�=+3D
�9���� 1����`V������h�����+��Y?����{
zk`�xA�����6j�o�7tK�n���������U��D	
Di;��G���NY�SR0�8���k�L���a�D_����I���d���w/����1�K	���*qg0�hnn�-��������h�i���������7�Q����#KG�^��)!�z����]2W�	B��� C��m�C�����+C{z��5vs��h��-C������*��o��i��@����������v�OO����Yk�%n��-�������<��^0h���x>B*�������e����t�S��h�;w���u�f������"-}����^^��BZ���m�M�����7�%n���q��!CE�-��6�oy�W�*I,���
h��������J��Br���Z�b�,�0�H#��*
��L�!+����&�Aap(�-��aU"���B�L[~e�����Z���P/�L��-�D,�1�����*eO5�!�(�F����3����x�F2i��"cL(U.q1z����y0Wz�T}�Vo��S+r"�{��-J ��{M��^2K�9�����w�h��� BSy�$$h���-] C{��m�b4gK��q�n;�����"�8K|7&-��n�l�.wH������J���};�,_H	I�����$�-���
�^��<4�<������[l@�����o:�==>,��"����Z������-{~�������aV�A�z��~#��- �,)�SW�A�;P?����{��h�qfK������S���s����?m��}�cO7�5�9}Q
������4��m_ ���H7���<��"B�R�#%�)*���{��M����}@���^��,�6&���IU!W���cU�/�I�����_�$���$����Z
���2����	P����8&��
IY����p����#Uu�Gg���X:������������)����������Y���{�?�G��������"���'n��������H_?>�n��o��UC�,�?�T�e\]5?��Rs?�{��{
�m�K�����������/����<�~{z�{� *nt9{<oq��������i��?����8�����W�B�������f�6��}���E���Y��ow������0�!�r�7tj������\n�z�<Y��e�2��s�|���>�g���`Bz�� ]����s�����7s������|�ll3�F���+�9(C~��|�ny&�=�r���9j��R\6�=��p8�lq�9Vp=��P�����z�:���lr����C��p�;��c�a|�g��W�u��L���/��cW����d���?��O����u���
��l)}H`}.�s�����{��X�^�����}>o ����QU�
h[�9�;���lHw����c������=��	��G?,@������
����<0�y��z;����F,�D�<#t��zY.8��h� S��b�� ��=�Z���c
]������
{��8���ZA���c��g������xfX���f��8To3�c,nwla�BQ�)��� ��L��8�����M�3~w,�VEc.����B*��n�����6��Z49��@;�yS����[\s"80�Z�gY�r`�&�y3�m/|���a�=��k��*�=�����s��qn����;]��x��y`=�t�t�	_��&�����jvz�e)�jb��i��������~eS����q��1~��K��h���
��@H�k�Q��s�
,B��;i(xS�q�&�:�|��4��p��m0. ���4�)m��\b+rw�q=������3bI	�����������LV5~��	��|95�M�	->^�6��qH����|n�s��m��$����j���@��w��`N�v)��,N(���>�oP��7�'7�pQ�~�����l�5�����*�]f_��W�e�)5��,��9`Uo������%)a������S}�T��N�\�;48XU/���k|5�{4|���a]7�kV[bp^D�����"�crD�9e+S�Mw���1�-�����Rl����k3��}V��n��W3c��K�=Vz�)T��w��o|o\d�k���?��7n���|�R)^���lq��V���W9O0��|��
��je�z�z}eqd.�]��Tu8�4:�D/���<��P�D������-�6��}�-��K�g��3�6!*������i}���(�],<�6�(��]gO[N�2��E�_��q�0�5\]
�:^
�d]D�e4�u���st��S4���i�y����!�Gs�A����x�FGqC�^��7S'mEx��z������]��j���K�p���Q��;_��]~FJm����m`U��s_���R����P�2IQ|����DVJ����w��vI=��(����H!�������;��Z�"����������a�>��H���2�c�3'�����c[�'�����[�f��
��t���wj�c����������6{�X����M��_������Q�k�2���C�r��L���r���0�+����a
�N����@Yq�Hx����x���q�/Y������>����]�<�B��R�L�'|/�,*������b������x�������� ��y���z��K�d=���mt`~&�e�~���(Q�h7A��Q
��`�U>2����R��(a����=�����8��do������Q�hs+�����N����__����l>��A?�$`�;�b�{�}������	SK8Z7�S�
���<���G���="��6���Y�������w�LJ�p�z���O�?/]�"��V��~h�f��-)+�^h��{n������v��Cx!��_T�����'�W�h���s	��m��R����{7���5��66$�z�O�����Cw�?`��p�#	�&���=�om=%sE�6�P������w������[
}d�����!`%E/��Zt��;�P��jY7���w	����u0�,�"n� ��v�������������: g��I�������}������5��v(��#����!��0���l�c���g/
��_�o(�F�����r}���{�1�E�&�G��
X�!\c�G�L
����&�y&���C>��b��N�����Ll��	Ry����s_3���";���r��u���"m�����@a�3������B�]%)����n�!G7�/^n8��c�����,��!=;S��E7�E,�vMsJ�������J_�2O�Ja�)�|�;��K��'�-N)��~�/�J+���y*�k�#�](���Wh��&Os�%������46��Od�^�|���n�E�=����6^�mI��Q4���;�*��A�������>�����_��CL��+]]����7;�>]Y�~�hl}��QY���#W�2�>����Cf��r@�"�+�}j��=JY�%�������3j
J��c�����<H����Nq~�w�_��l)���#���C�A�%d�=��|�@2�$,�z���"M}������� ���5��0���Y�,�]V�+�u���E}[}������e���1.v{�R�����=���d�L����G�\�`�#�����N�"67{�p����Gp�V9�9������+�u#�������D�s%���L��yX�v��3+Zs~�����������t��@�8��FQ��6��k���7�	��q���s&��L9�� 6�\���� �!�?���X�">��, ��8��n�v���D98�GL���eX�3,U)��L@��:�����
G�dq �Y@���n$�H �hB���?�F�����7t���&bZ �*�7�����,��O��p����0�x]=�V�t��:��/�j�������Q����Q���6��*�G�?������v^�{6��8;����riY.���r�"�J�����y7I����
���~�6���Mc|Pi�4^���j���|��H���y�����|�5[�t�9Ke��U��>��.�Pb���������{@�0 dZd�p��)A��������m�:���V������?�V����� �I�6ov���������5)�}�+����\@��[��]�Qk��l��U`��0�����W��;��&�q�	-��A�t�@�������aHrb�e53NDi#�Q��/�4]:� ��M�pH�������+����i1:>(�5�d���W�Dh{G��y��UA��A|����V ���=��q�����S����}z4��h����z5d�����T�y�S�|����*gCb�N,�n8��G���6�5��%�0�J�}`���y���`���
�m�7k_���a�Re�V�'f��d^��J+7]���7�����(?�)��$/�uP7$���y�������Q��i���������E��!��8�����[d����a�N�rlLu6	_��H5���e�MQ�&�U��,�k�y��~�����>	���:���C�%;,�7v@
8����K"p�,Ta���B#��|P�����������\��,�h���2�Exc8�Iyn�=�["t��������m�*�B�G�"�o,��X�.L����I��v+/��&\�P�'���2�����C����^� �LP����r@xq�O��g��(�7�*�D���`��uB��f�Z�*�e�ZZ
�4_tU^�>���Y�{�K�����b��)C���P�N}��*!���K��mt����D��@��������^D���4�R���w�e�Z��KZ���l��<gb~]�e���M(�N��"�z��� `���5����ci�UX������,g
$�
�:]�9���|�������4�x=���wi@.)�����Q6�.�
E��cX��U[����[�����Hs<2���g�����j�b,��=+��"������;�/v\����`9�N�����8�9�]����liel
7�	� ��P��E���O[���^��!�m[�����8�u������$�������XU<��Q�:-r����t�2�47�=g�O�0�oD���x!�������T�.��\6�Ul��LO�EV�&ko���p �qW�1��|�5��5Lv�-����������^;O'���b�n������C��b��J�=K�C�#����3}������R�rt�3M�+�r-���6�U"�<Rg�Tl8�r.�1�TT�#����������}*��e����A���l�]�,���J��<S�����9��u�����l�9��~D�%N��p9	_�GHR�gY$�i�}��9�PEI��tdG��P��)���[?wK8>���P
MQ]��#�pFte��9��C�y��b�6o���g��q����_z��Jk�������,s�����HG;7����*�8|�p�o�x���:�y.�k��xQ	���M�����;��8dy.k��$
;��o�#�8��U�P����.Nk�
)5�M�����po���y�!�%�xn	�z��>�-�0�e7�x���Z�uR��q>���%F�S�X�qf��$n��Q�����Ih0���Y�1r�t]Z����9���>~����Lu}[FE=�����������%a���2#}p�.��,�#�}1����n�O<��o���6�BE&��h���Yt@�D6xf��}�
��^�k�^)��<���6]�b�E��3}��'8��
s�M[��7�{�y�-X�	�"��ef
�e�yP��u��LY$�M�����
Ve'-t����B,�>u��>��E0�$�za�gK�})s����7����%Z+s"X�W�9+i�h�Y_�J����@����_j���<���N�����L�4�gg3a��%��U7��d�G[c�#�r�eG�3�����crRKM���w!�����!����#�0�6
GY���b#��5��Y��s_	�����-QSXN�A&#c���V�������O_T�9������+����dU
D_;����v�I�Y���A�X�p����^���H�����1*Q�Es^	��+����8�e�-�z��d������~quC��N�|B��B;5�7���0��	*�Y�@f��<�!���&G�H�����&G��t�UY
%e?�~�1
�F��8-e���%`�N{��
B��6cp4c �8L��(>���dn��4�	?����u1.�^c}9� ������H������[c�3;��2���4��&���m4������X�	�WF&sp���\�\@��-��cH��qc���f��t��s.K>
��p@+�X���6��.e��5pT��Y�W�C�s/�Jq\�A�h3 M�HCv����,2g�-1����F)���D�6U���m�<��}���,��^�������9O�M>d�M���nO"�=����tD�	a��f'o[����A�V=����,�d����H�>�h�C	�dQ���u��T3j"��e+�<�U[��1#�e�{�'g���������[q�q�&k�G�0K��C�^�x���!)
�e������1bj�5�In����6WLi}r�%�0G_s8��;����@f9�~TC���l&	R�M}�0D�G���5|8���\#��/���R�HFn��AcD����]|3�����=���/�;�tF����{�i�����v$k9��������!��.�������os�jS2n�R������j��!2i������!-#L�cq����Yj�����'���n�7q/Tq*$��KSP$���Og��f���B�F#w���#0	�K2��6��!oJV=_��c$�gc�Y�o��qc���Lg=�t:�^e8�
����(5���q���(�����'��
�`>����^s�Ap�
��"a/+)L����),�0BG�i�C�v�;�>���T�=Xn���<��\�z-����T���!�3�X���9�Hv9A6��A��R��f��1��(:�`��j�bdrb*�\4�������{��)��G_�"��?�,�db�+/��J��`�������(����G��������Wm��\
�i�*B���������]V3;�!M��J�)	
FZ��k�Q�uA���F�*��m�s�����5�i�k4MCi��*���Os<r���Dn�����OB���=��S�7��84������G,��N����������@�>�J���;�~���e�vz2�����������Em����R�O��;l�&��8G�T���xA����������,*��:T��/�k��XR��G�B�c����k��N�{.��|���[��x �2�%����[>������M2�}��f��C���Q�at��p�m�(�3^���i��f*q�"S�!\���=�K'��%�@�~�^_@��s�t�vY�c������T�]s�(#��zxn��I�������
7�	��e��Bx7��`��8�
��+�GvW�Zg4?�3������8��5���'��m�r���%C�c��F1N1�_����~he�x�U����cL������}@��+PD���{���}��zu�|?(����"�]g����h�%�K�M��K���Z�&V�Q%�Z�u`�������^�yPC����.\w�>����+0��W������3�f����i�T4���M4�
�:�Z�l+6�O�#_�>R_b���	U!�`!�UJ���9O���X�Kzk�\���-��?]���L�D�'"��Y�>#=�"P�6t��"ClrS#�8BT���x3e�BI�H��6���}�IX0C!�0a��y��*������l
���8I��S���K?��i&����Km�����1`[Fm_�@�qNIcq�\���Vbg'-�&\���1�nl��Z�E� n�/� ���D �f���2��Rz���*��9�[�F��:3��.)�|O��:L,ecmF ��C{2�4������e����n+�aC��elR�Ac��$49�%�gO��8���Q�K�h5�Q�S�.��Z��`]����TH	�7���)�l�1T��S{esq2���J�fY��]��m������%���U��5n��t_X%]r~A��
�&��� e�IDmf�GS�� #�=����iy"�G>2���~�R,����`����Xw�?'$�4F��t�z�"������������,>iH�u��L.�@��n�v��g�YV~�	��4hKK���c���S�a�����^<���
B���.�����A(��V���z@�L���Q�W*j����n���|��U ��f�la5��Z�q��S�3��`���8[0�����&Y��A�g7��6,�?�q�-1X��q�)�����d� F�T�i���I[U|�����u�����P#v~����)�tR�}��pM���;R��)V��w��p��<qq#]SBXs;��]��:{r(K�m-R"G'!Lf����kK�����L>�%�C��9]��v�����
}��|���59TXM����$L,�;��0�OQ�������[D�Ze�K|RB����,������	�g�,��C����nbe&���L��1M����U�E�Bc�`�D0��B�
�iY��8���&"
�&����=r~�X��#9��(d��Y��=������^��$�k�!�I��;��qa���M��,1Z=��h,�'GmuQ
����n�����\�r����m�'7��B9(y�`���K=!,�t#���|E����#�����MF��:�l}�)1���P{�<N��L�v����PT0�6[�-4*^X�����hU���~]�!�}�E�
q:v$X�.m�gg�����S �%7��-�@I�[����l����������dY(�j�����%g"�F(��./�z�3~ad�0��O��
K�un�a��JE����S�Cd%�$�|0�e�O8���3�5]�q���&�����7�$��q)�.�l�X�l9�#��<z
��l&��-W�8��(��V�\C�N���?�~�U�����=�f�pcGS�CM���;Zg���]t������8��^�cq�9�`�j��[Y��]��]7��#\�^h��Y�<��\� ;��Lq�Od��]7��:_
�b+�j�2��(*�^�k�� P�Ld6���26�U=V�|>�PP���:�W�j��_D=��A���������������qr����SMJ�6�����L��i;}��]["X�R�>|%t�'�Zkk�	���_E�J�������\�Y����q^�����_E�������g�
k��)��V���4<���7Up�##$K�����*��bd����t��r����������E�N_�M����Y%��B?����i��Aw�6��E��E�V�>Ch#��,�E-F����z�q�Ac8@/G2�.���j�����+���#�:A���Ecj�q���{�GUd�<,+h�,r����<���1I���)Y4�%�$#��8������2�7h:`�s�N����3����Y��	�:�cYB.N�/���O��	����>edK�C�>�Rb��u.���9�dq���k�3I�]�m2��F^@_�%��2��a'��t�x�|��n�7��@��TA���0�B���-_{J��0�r-K����_%���r,��(xb{3�Gm�?0t�@.UK��\L:���8���T�K�Z ���z�
���i����Yx}��
N�)���������B�p_Dt�,"Ys�G��47�bY�&�)�evN��r.�k�$v���s02(��[��Y��(M��
�*w��
 ��,�"��\�
��
�S��*�&�x���L��C��]�gFTE]k{��Dm'iy�
�rrm�����y���P�3qpry{�������]���<��,���l�
8e!+&o#�=6�j;�F " �;6$���~W������m	�J_��2��7T�u�o��h�x������w �:��So����Z'���^�dh'JE0
[N����o��C8�eq�:I����H��H��O	5���4"K��G�Y�t�M�U��1'�I�+���s�d�6���B�H�U��)���������2P����/��
�U���7=FLcOj9�����(��pq����*�T`r�xY��7eQ��W;�:��@����*��eB�8k�;��E%1����Z�]�T�Hk���FH>�����ch[M��������N��|Q,ZY����xI5�]N����0�Q���y��^�f7Z��<���XI����^��l0������
}%�[����m����������q�������M��������)�+�����l�b�e0�'9�I���7r�� k�\�uq����v�{�'���"n�8�]>���}2u�����2�/au��*��4���Fw���j�K�k��"�@8C(��Y���(�
���.��Oc$��C��m6~'q���eg�8*za�����D5[�`W%�)��^1�/�QI�����`���,)��%����F��q�C�-\!��Z����g��2��7�5������Q9�[���`�j�r}����<�[������y�D�������v��g�&c����Q�ta����V/�To���d�67�:s[��!��&���1v�<����S.rj�;(irH�JeZ��Gf	2I����y�}TQO�H=�(J1)tt�YT���
�5�`,5s�� ;����1���� ���:��x��|UO���q)1�Q���(P�����m���pt�������Z������275l	�`4��{���P�M��H�;#:NvdM����8��M�2�E��X�����~�n��&��_�<6i<��1X�,��y��
�����5�r�tQ �st��Ui�����Km�T���
�<�����a&����V���6�����4�B�kw1X�I���SW�R��l������N���^j&�D5�d>���1U��Ztx���_�L�Ek���/���g����^�v�MQ��NC��C��Bv� �EK,zr/�I�2E9^����p�|�����u����CV��t2	��0�3�z>��M3$d0�lB3���'��Z�X�B�4�����)����@Pj����b���m�
e�-c��8CLr
�-�m�{~~8F�R�y��ag2���B�g�8���\�OmR���k#}���'��m:���{E�v���R������`�dn�_`���Z
����i7%2#n�zj���	@���2�q����2�1�R���y?V�t|�E77T�<�y��}��yR����F�a���h:��G������(�q��������c��E�/����IN�-3�O� Gja�
G����5�����j�ystS#`do�2�=��LZ��,�I����p�s������5�Q��o����|>���/��y�N�q��d��VZ�
!��U
�����8r���k����V�y�Rp<;����:�������g�W%EW�6B�5����>3���)t����$��a�c[W���E}�vR ��(�:���v!l�qg�`��49�7�]�������Foi��sl�����!+����s��5#��p�>�a~�P���}!��a��3�,���%���u�� ^��r]`��s�t���B�"��sQzj�'6�@A=9Bv���_�f�}�w.|�d�>�F��/��RI���|b�gK.8,�����*��=�R�D�f�h��d�;(F�UI>�m��Iw�*�������X�Q0�������2�Di�u�Q/e
��&X3b�-O*�ZM�C�K�6+��y'8>�����4Vj�ZzQ��tc��������BwJ��V��$\z�������B� L�����D������I��mD�'���Rg�}�s#�D�~���!�����������+g&���5�"����o��W���e��"�";����?u�l��e�y
Q4M�GW��_~�\���v�i����U&�S�T�y���Zq�����Z+}��eDW�V
��\�0�nQ����l2��7)� M���g�~��\�_dgh-"��\MZ���5z}U/�Q�xB���Om2��c���q�i9!��]���ei^�9'�r;��`��	������mz���=���c��2[�j6�$��2&b��/BgOP�[*������(�-_��F5Xf3�Q�����y�F%]���#��������G�d������K�	 _�q���%KU\��4�����!��)������$�g`*�e�������_��q��{�Kxx�����e��A��h�ne�F�����f�d�f
���!"P/�� ?�c%�\��'B����l1?�Docu��J6��}��0����3�9�����S24��F���[�}j���2z
��
�
|��D`�
:tx�hD��
W���
�t$!k��*��X����P�v���S�.�)����x���x�������NO)�u������lG��������5u�)m������P���j?8]�
�������8�1mg��fF'4����a�e�Lh�05���j�y�O���!"��W�#��bM� �p���|Jd�>eL��	��!��Y,������rY�<�����Fe�6��`�t��E<^�_l����De��V���������?:���y����y�p���(����7������5I��Gi��|T�TI��k���m�$�\\��;����y�^�g�A<���g|�Hu���)��;��1O�`�g�����I�q����b���,�2��u)j��,D�����W�^"-��d9��~w�"�����`��6t��Q��1y����jfr1_�(3�,��uKjk�R�����j��RP�:��dU�8�N�ET���E��r�r�M��h
D#�*%�^�������
S�B�mKP�R8$����+���T����sY���z�����v$}S`AP��}��'��
|5��qd�-E�S�1�hP���H��4����g��B�!�q��(�WbI��*�3������t��9KP�,8|����A���k�4y��HE*Vn6����uU;��Y�R���/
�:���VZ 3�'����������\���$K��n<����Db���|��� -�xFz���vGtt3D����n��������DN�jC\T���Bj�m�<7;�'`���k{y�����e;=�A2���Dr`���Y��
:�qt�]&�B�oU��b8HZ�.�� �1�^����}�{t,�rt+�Kn��|�d�Si�f-�,X#3����g�'��w������M`�n=}2���/[��:�r�BME�$��'[�������q,�2�������Yn/�zCE�n�dl�\�l;�E/��,������?}���
��-�����������H������0,�����T�����(���
�Z]jz�bd����p�-qsN;�z���5�����]�y�#����-rI��X��0�a�+�C���{��5xk�P��*[E��t���6����:&@{�����1m����Q�K�G2=G
�gRc��~���1�����WZm�&b��_��z1��tn=4_��g�5N%�1�C�5�����G�0�g�zt��A�Lzn�T5�5��:TXyC�$��$FQ	���L�u��U]E���U7�1 '��]6c��%	x=���TM�u�|a����Q|2F�PV2
���h�&�����y�Q����l�o
q8'������C���K�k���Ccg���S��u�J�:�
�r����~r]��zA\����,}(�s���t)���
�VMboelFD	Pc�����Y�^�kR���{!�E���9Q!�g�1�����wiZ��k������_���Z�B�R�o�����F_G14�<���7�����W�ls�D_�@,m�`�o��1,2C�DE�m	 �`j�IQ{���M~pdh����� Q��H��=:���?�Xc��G.�������.:�lV�,����J��8�	f8���/n��G���E�3{G���
yQX�����:�(
��+���b���U�O��A���v�C;�8eN�A�=
��Y����Rk�5}\Fc��03V���Roa�P�4��%�W�N�l*.��Kj�������[G1����yY�g"%�)2��0�����r	=�\a�b��y!��C8
1d]>St3�������M[7��^�X�0 ���,�|��������~��}������d\�Lg�kWH���~v�b 9`����R�<-C0V�D�r�q0)���^eP_�7���t��
r;0�U�����+6��s}�D85i`�^$��B�L8��X.�����FDw�����,Q@X*�\L,V��vN?�X+!`m�VK�Szm�0���N_?2n/�`��f���x�4�Q��]��!�vH�
>�� ?�K�� �����!�#�u>SJ�>��P�I���f����V�W"B���I��3:@���`����n�C��O��������a�&Vh@�)���%2�/mn$��19U��@��h�����$1z�J���!'zP����b�@��z��JQ-��=
�H����0�E�
$T����aF-4�����-�i,�4J��&��m)�Kg��fG�0��*�j�*������Hm����w���e��v_.�Q��[��I_"��tr��������sT���5�gf�p������H%T��F��6K���Y�l�Y�U�
�@�'p��;�M,����yC�W>#�����6���6���d�#�/����zMk���f�+�����Zo�P���3���n���C��I�\��T�=��E�z��;��Rs�8�,n �g�%��
��16-A������a|���\�6�OO�|,@���K���D��)_����QQa�_Z��[���#oe��(J�J!�cPQ��ew��^�]@��[����:jWG�oV4S��)T��d�s��������%�BL�B�B���,\'��>�R��g$)���^���OY�������b��h�mw�Hdw�FQ���Y{T*���i�������!O��r�s�Gy��/��6I�o"&�Jg��y����4N���C�)z��(aQ8�����Q	!��������i�w��T���$�D�d2R��*?�T2%�H*�K[���Z������.��~���d:����4+x�2�����]����O��.����N��y�2eh�@&���~�+;����o�w�='6N?D`��&�q��3F�cd�� ��{)�*	�$�����]����'[7��ex�2F����j�j
{�d���[�tq.[a������V:��f0K
��'�d$� C��H�QAW�,�F�N�S��'r[y���6@��@!yT(�m���"��}}����5s��pk�2f��{����J�j��ZA�[�
15�Z�������U��8n��t�^#�-�5�r�������4VE��(�%gpHR�m���7?��^�`��q�d���z�@������<~�+;����$�F��5�gkB�B4!���������Z�^/,�K��K��kO�����;�z����(��m�f_����DM�#l��(ar�K�$��P�������D�������*����y8�:j���S�"����(�c���V*��I
���3���M��R
%�VzAE?'u�S�(��uz���g���_���)�@o����ki�|���6�Cr2�dL��$U����!bdC:F(�|�W%���*�)��q,�=e��#,�L,:�4�����	�`dxZW��F����)�����+S��`&$1���`�g���2�����F�RqPR<cS���"��2�9%���@���+f,/�%�_u[����>�)���J�E�n�:��d�K�^��aG��B���)�����~=f.�S\�c����Je�3��G���
���
xR��d��*4;'
�i7��0IU]�t2zf����N/OY��4��:l��I��j�~�1�K�����2������+�g��s,��xeLYl� &u"���~�(`��&z������
2��h��G� j���U$��.���J��[H�Q!L2}y�����D�7�	�\�S;�U*�ZeZ�~�����d��j�7�1g~��e}�P��}�92�m�"���*T��{����7YqL��FGVg����7��<N��
:��!5T��d�Rms� B���1�=����`���8[�7*�KV��Bo1� ����Oe���u��������UYt��f�`�a���[��8�XG4�G�X�;����4���p�(�Q���L���E��z{�2G�`��It:�0v����#Dfq7Q������Oi�u�"�A%������U`��ah���i2��n������nT����������d��%��I6�H�
cxH���d4k�d;d�w��j�� �9�R��%����\]pJ�?�Y&|�qV���W��{�%������>.����M; ����Q(C�Qu��K��(�-��\�e&-�:�-J���|��+��}�{"�������;q>D?Gc�W���t�Bg
������������*��_�����v�~�h����3�2�Q7�2s����3�\�H6#,��
6_R��%`CV�.����=������r�����)y�����(J �1���T' ��9�SO|���!g��*��nC���n9�Z�"[�
���"���������9#(���6���t���P8�Z�r�d6���Y�w��g�a�ya���+J�A�.�C��N����h��)wT>�:����~��Q�Y�1�j���Ql��"���i�E������K���y���JRfP������z�('A����59�=��'����]�T�'�f���v-+#������%�8��u��#SSm�z�Z���� $6<�m��]��V���1�D��(&}�8��EDX���N��>Tj�������z���c����� �X����_��{aLkJPfX�� ��BE_��d��JOsr���CEl�cdfp�w���I�l�-M��f3�4�h��V�aT�s�T�5J]���@���,@��:eW,T:P����g��iT��q����������G��������5
�����C��8����q��
e�m���~gSQV�@t0��r��]V�>�?��J���,��>��X*:�v��\*��p���k"���r��])?ro���K����T�5�p��
��Q��`�Y��e*�am�~�	�V��*��8o��}h�������R;&�?7�L.�Y�-����o��������i�w^P�����}����/V�0�l��0��x��M!���i�apD�x�E����{ ;�Ql�%#�L�b0����8A=��lB��>�`�����|�h�/�#���fz�[_{PR�H�[h��"M�p�u|X��������|��!�����XM�T��
�'��o�
�e���dpv�U�*GK�A-�����i��h��@J}���p�8�P�P�:��3�W��I���g�y�hlS�I�<�72��S[J����C�<��l�C������6��3jX_�XH��]_���o��k�(�	c������5o�S7����ac	B��W�i�*���h�whBU�����!]�-�H�P
����S�ez�h��mm�2'JDcK�\�b�@���VG����>�UEw��d@*��4�50<��C�k��"JY��D����C�����$W��Y���03�����|�[X,4���.�]R�` �A2"X���#2�~������C������b����8v�*!i=	�T�����A��/�+Z�G=�r@��2�7�E/x���eS����iJ�M��)�Aj��)����)=�*Y��)���pf��
J�JqT���	d�S��p]e��������
��P����g�W����jo�R�OCy�1V��c!P�l�9�'J`���O3�K�Zg%�d���*!C5�HrG�JT0!	}D2�!�>"m���qP1�bI���:�XNEw*z��FL��%��4��SW�b��uDB�M
,T�N���V���AX�:�����q���~��� �CUs��u���(s�b �W��!��H��z����B�)�:����	���j����.C����>b��U$��7^(��b�Hd������h�2%q��W?�q�(�������K��!��Z2����D)�����M�2y5UJ�<3J4�B�B���Q����@�����
�1q��cqV>���:�2]2��������������)�����U]A���V���q�o�?�~�"#�}�����U�)c_����;c"�'���)x]���������8mS�AM� 2ZX���Ve'�N%��p\q��2��sP�T�^�lzU��y�(^��a��y�����P�3k���m�������z'�,���t!k������9�7��W���	�������^:�w�Z����P/����0��ne������#���2u��)5y������/Z�6�������%��{S��Z2����w�h�S��ME�����W��kK�*���C�z���g��i�U�����t���8�j��pOA��G9@} �sE�D��BFS�s��|q�e��$Z�n���L�0F?nW�\	������~2���s����T
�9���b�[D����A�l�y�N��-/�#\������'^�gx=�yRO���>�g:@Kb��8�����:��h�3B����Hs��������V/�:G�?$��((���M����+3,�'e���\�n��.���s�oy���P{�I�B6�}����J5Wu���TS�����*�T��8[�����@)��!1�GHd��(�WUi�}����IE�33�J �v����[��	.C��/�hx���������$+c'����7^0[-����B�j#T�tC�5�tJ�	���@������������Z�j��O�������>kZd@�Eo0Ps���q2\:Z����S���A�	B*�����wV���S�T�D9*�kBum�z`� ����HVn&m��stf)�=��9�,����N$�H���4�E8�A���N�B��1R"��i�QPB�'T��K:��AD������+��������Q����~ur2FH�����0�}OF	W��8 R���M��5 0T���e��9������
���RhT�:��}!�z������z�:bc��B������~Q<RQg�����������%�B_�^�=/�
���D�H����%S��:��g�0���5��aV��y!p�M��Srr��8�r�?�05h
`�iTn��c�7P���\c+F����Wo�;C.�n�r=��>���#F�h�����U$a
*� �y�����g�I�q����m��o[�$�(�TP>������S[��z���!x������O�C2���	�3'b#4�>_��B��(Hr��(�T�`�
$�;��8������O�Js�����R��A1u��?2��YTL����3�O,�B\v�lu{�-�M�*�<�.�Zo#E�������k�p�6)H���o(��c�B\2���R!R�8A3?t/�<���(|�PQ�~Z�d�c��7��g��[�K�_x��&T��������j����+�*S����0�.[��:��:uN�f@]������H��@��!t���b���!��V
�E�k�8���^�'�O��y������0�!�T� ��
�
����8���J�R1�%u���TRU�;�l>���|,[���1����T�����b�@5��ug�D�$H�����O��P]�3����$*�g'��lE���a��ap2;��/�7*	���Tp/8$�M%�	}�QS8�oC��t�RaI��Z����aGX]�2����G��\��;������a���)l�}`FT����@b��I�w�h�T������Z*��F�za�&���e�$46��j
�����\(����~/Bp���V7���czD��$u-Z�����Cv�4'vr=MZ������1B'X�\:���']cF�B���b<":R�������W#��KQ!<c�~"1T� c�R2��6PWkR�t+S��p=����:2u9Z���4P��`��
2W���f��N�����LzS?�
��QA"�6L��a�U@�,��\{\A�<��XW"F���1��������&*��*]�'�z�"���>������NE5SDW %v��<$>*����
��a�����D���_2��H]lkvPW��� _-����lm��L��w���z�37���v�!V#r�i~�����Bb�����f�r���?�P2��Y�1�z>������y�z��?���~fA�J�5�xLR�G��_K�;D��0j��T�";���u*@����3L�r�� L�	dj,�q����b|���9)�1o�a�����y�i��,�k$�_/��Q�����g�W`��o�����X���ju��[]�0������P��rR.
\\I�	���a��Q?���S���,�C�f�wq��A�����Bd(r��������)�zo������M;��
`��SZ�N�s���
���HP�BY
*��w_�;������a��
T�@j����~W�r-Tlv?�[!�Rv�n:�T_��H�##{�H��U~���7�M�CG���2A>oe�Cysq��� ���=}q�~�X���uD�Xf�L�,�7�C��a��(�4*�*pf���HF����	R����Q�����$|1�����r��6�7�F^�P7���V�����UD�AeL����8P0�x%�i�.�Q�����0�}6B�����i�It��W�
_��e��=m:D$���(��@�(�������2K��
�/� a����KF�8�T,�#M���{:����d�8s�j�=� �q%���g�� k��
�{���iVY��ER1b���a8VP�m��<V���������ld(Q���2�
������>XX�������g���^����~��d;��W0���<:v#0W���hdq�/S�IU��fq:@z�b���p�i�kM4��PTM��LF
Pq��L%
���0\}�T��0)'@� "�.I��P�����9���g� �X��>���>
H���5��6�A��\>��N���M*��N@]���V�
"Bc
*d8�nJ<u5����7w�~~�Su���J.�t�L��z�@�y��u����-+@�����2����zK?d(�41�����o�r��ds�(����}f��
u5&���0e0D�����W��MQ����0 �#�"��S1T��@Es>�(�n0*�"�UC�knALp����|������
0���@���%�U"t���Z�K���iA�M�>�3�:=�{��2RI�
FP��B�`���|��RE~_. ew~�<�q+���8�mLg��o"4�U�I2
�s�gp=|.:���CF��]-�MM��p`�*�_������13��aec*J��"�x��z��!�i�I�`,����wIz������/�1�P��t���i��3Q����x��y����5Z�q�}&��u\���b�y�s���:A�	Lm�����t$������e�i��a,�Z��)GG_g��V��m���d��I����4� �`�4\�"���H�[x�? 
D��R!����Z������p�^�&Cv(�$ic8e24���A�
(�Vt�j��4y5��dK!����.���*���M��c�b�%�X0n�-"�,����u"�uK5�k��]�zx����l��
Y��4G���sV���������E�y@�v��YD*�wf(_�Y�$/K�E�pK�
��$�����.�� ��	��9��t.�k�$I*������O��^�'����}t('����nx��x2*/������G�y"�9��^L���?_����x�����������cz�T�PV�(3|*A������R.�M�W��G�(�`��������b8�f��*0k�^�R���bD*L`"��%C����0�f�PW�I���O�Tn874�p
���F�uy��JG	���0�=K�!�Y*�+a�Y��!mUf���{V0��8�#��Q���������!l���/:�gAI�����:F�� ���d���J��QL�8nm1�j?���1LT�a�@�u=��s>�����_��H��+KY�!��GE %�,k���E{r��@�vi���������."rx�0��M�R�}9"�[
H�6��C�
�����k|tB:�O!���*�"Q��X����:_�
C1��b%�gq������4*7*�Wy���
o�d�����z�?O���7:��D�!B�%EB���{�b����t��X������ >�����5��./X�*�We���T�#"9���4�T8�`�}w4'l����S9��%����I{�8PaP�t�c*:Ha���2�T��=������)kT�U���GC	����o/�1���@8�D�i���+�O+��D�\��V�d�u���w0Bg�_K��GG8�53�� ���C�a ��-��:lt(

����p!#��K��;�N�n�\�m1|�i��A�����$��p��&"�~`�m*��o��,���-*^���!��TL������7IP1�BA���R2�q���ne���X�#��-�^e�*V�,��R�*����X�b�z��Y�'�\�
O��TO2�f4'7R��'?��td���{@\��*V/3;��}!�q1��T�>�#���	���L�Pd�t��A0�-������)����/ef#���������l��W�����@+Fj��Ie�B9+������L�ou������lz�����K���g��>C#�0��������	��#u=���uv��?�E~�A�d� i_�M���}A���H:��<���~��G�m�`�PQ��
����(���|���XJ���N�������U�3����=�]
�d�VEe�.�Y^��
���3G����'���w���R�TV�Jy��]<��H\R1�l��?doen���;)����� �������������X�9��QRt�`�!�f�(I�h��w+���O�B� �]��� `qOi���e`vE8EWB����Q�����K_���UT?a?Y/{�kAR���2�\���8�2����1	�O@{���`MM�[��"�e��c�
���}	?�)�����KCb�Z	�O���M@�q��Y�7�"?@��PI.:R8t ���.�o���f��I����.QC�6�9�PcQ�c���p���}!_���>�	C����a�nv�����]�ya-$����0X���!\�U�
��a��	#�C7��������`��X�2�!�o�H��X%��G���0�[$h�� Xh�Ao��-���R����1(��!W
�6��kI���`"�[I_�M^4�/��1��b���<�~�0�E������r
DHI�6�|������+^������p�Y�Z���~PC2Vv�8G��J;h���LHp(��N�sP0�5:���]F���Sj�L.(�������|�	L�t��|���w�54�a �{D]��z���a1��Pq�dP�d��gaYw*�u�VB�TK���*!yn<�8��'��#�`����9�s�8hQ'w�7@����� )Z�8c|]��g�h��dP�
_���#
6n����Q��$9U�_��+zR���*��d������a*�yt_���6�\%HLd�p��Q9���Rab�Y:N��F�A&�he������}�^|Sdc+�%���[	�N���&�'Q�I�Eylf�-��$�,���+/��S�|.��d�J�1]���bF8�C���@`��)YHF0����~S�r3��:���d�h���1=BS���v$m�6�n�N6��:R����	D��]���jr�<;[f�@�CO�H�"�|dF%Cg��#��&��Z�Q��j�^�1��*�<
m5��h��R�D�q\b�ZY�:Fv���u%��������'�n@��	�r0z�z�/4�z�l��r�t,�l�����B8�*`�dg)-���v��1y44$�3B�@/�}n (��`F����P��9�6)����Fu���/�,�RL�l�,o�Ku�j���T�zfm�����������Qm�	
P7��<�Dx�Y=I3��0�e"�����h��v0�+��@"@]�]�V��1��� .�~���V�����UZ�Z�����@��9� ��V:��A�����a���[�Q����g�/s�JyI����vY.1���D,�h[�ZlC����!#^��k������1��5�#��m���x�?[�@�^�T�%T�W�*R�J���A6.#�Q�3��s��r��8��}Q���:�KQ���L�`��c�n��q�01�
�oD&C��xP�0��;@���wP��m�Z�D���MTte@^���M��Pt�{�����k��S�"�+��/>�8���[{/N
���C���)iY���>��;�\Q_|����!��2Nm���cR�uV�*�0��E"Z��}�,��/Pz�+�\�c��Z+���0������/�,�Nc|����6oup�8��+����<��� V"@(�h�X���to�C+��x�8�Y��K?���!��"�!E.��r�	e����"����qG<��:9����g��*�Tp5O]�k� $�@� P��������p*0��?�1���2�=R����D��iTJ"/�q(����`��;�a��{r�����A���`�0�vG2�L�<:%\��h���"9����1�������(�k#��7�w��z�B�U���q��T
:)���d�G7��pJ��
�S1�b<%0IG"�p�>�Zx�����Ul=�E�!�����NH*��yq@�d����W�bQ8;{E498r�������T�O��0R<7C��+��_~�%�E�� �2�?7��9����Jh4�(���T:�w�F�8�m��0
���K��87�3��7�����1I�������}�0�o�u}P^�
���"��ni8�� C���_X]M�����n�7IrY���1��&������f���|4l���-Z|}@���N���#t�>
����4yZn������i9���a�!��^]2���X}��D}�%K��q�����'{�����sFFz��l����Q����J�b8���\�U��I�Rp�i��ju�]z��
������Q��uaNr�@�?�"Bw>�������$/������2��g�!�GF�Se��?��R�S��8(���8���a��(C��!����I0j���4���|.T|��1�G��Z���F�_���0�x
}=�S�%`)��a�'�s��N]���Po!",x�T�Kg��MzY�,�'�[LK�DQ���y�.�h��X�{Ay4��D���uvC�q�d��N�����+������UU�R���V�c?�~�q�^��T�erN��2�AYf��s������[b�f�=`��1���('\=��Pd�@�
�����kR0��9g=\���\!�g<��2O4@�F����C��!���Q�T��,q2�sp"u��vk��VF�� �{�.5��a������T�`��
��A�Y9����MK�Lqk�R{�uidf1��NN���Y������T��c������5�K������	����e��A�&HS�`����P_�j�'�s����
5JQQ`��j�lu�$a��������5�:F�3��
<�B��8�cY�oZ72��1*����G��Q�p=�r������Cl������s���Dx"�
G��<
�fP�A��e[��E��&)
l��:M���e���T ���)�A�	(��Ahrht<g����`OR�C_C���>��}X��w�"�E�v�-�sF2<�eH��	�!CPQ��b"����U-�}�`	�Z���"ts�~�0�}J��2N�
�,P�q^biQP�� m/���;�T����]K��q#ui�v����=|,_��
B��Y�I2�6�����<���;�@,C�vmd(�t��v7��t���mvEk@Q�[�m�i�-`E]�����{���Ub1�:�q���F�U!�N��\e*N0#B���u���e�Pn]����v7�v"��F��.����uX�0=L�NZ ����uRk=�� ��a�*/�,F�}��~��TIWf�S�������*���t�jS���C��T#;�5���@���"m�Y#P�S��Y�����_�K:���{�tt	���>woi���_d@�:'O�|u�����}x8Kq��a�f2�����.�u�)&b�F����e�9��b�#������W���c1��Gr������OU��zq;���b���o�c�o��!(�S�f������{�F�.�Q�|��N�]U�r]��T����T������0������=�#A�6mc�,2�*���?J���j�"�t��H>J	ay!�e6D��IFT�g�PTL���X��uo�	~�U��#\fL��cKB~��A���R�\4V=�
���(�g�v��GT�����Y����7Ok0��@H�Ni���ML"�tp�%�l���Ak{3I����Sqr�Z� �\�����]&#8y��ci��s���$Np��Q��(U2���94I�|�r����X���g��b�+�8���+[N������0��U6	�m��N*�'��<��s��o]`�(�B����N|a�kU��e&0<"��r��e;K���S�t����C1jC�)[���6��*IP�;d��(h"fN�
�O��{���~���*+"L_+
� ��OG��'��uf��K�A���#��(��u�V�>A��\�t�,Q�4�;�*��������\.u��@I|+��+�5�����&��~NZ�� :�z���3�������[)��|v�.�NEV���N�4��Dkf"B|��e��H��}���X��@���Q��c�cH�Fv�e(��5���H���[����%����N����Z9����p�B���!'#ABy��nC����""Q�B��t�!�fX{��5-���)��-#D�`�j����!�f\TI�&����y���Z��0w��S���1�d�j?���z��W�T2�[�VgC�oS���%�+;v�C�)��LJ��w������[�K����&q��T��|��Gbc�	��V��H�I7JS��fg��E�����M�8cn��V����%)D�t�����B�
�6��
���]D�L7�u��l��C�jl7�
����N)CX���I5������5��D�![�R����p�~�w���t���C��{5����8>�c>R�@����s�I�LU�����C<��� ����4���
`���PI s����
���`�h�N���^���uw#_P�@���x5�$r@��j�����,��X�V�������`�J���(�G�U�����YM��?X�B����c� p��hJ?��o��4����A������� ����/H��nOl�v��FU7����sV�!!���eA��A���
Qw����,�h��gk�82��J������q�3|1���.@�nnc2PT��*o�a���d<�fc��8�{�=R4P��	���~�w2��`>����c�� B�TZ���\Lv*�S���E?���e:�*O��T��"M����d �r�p���1"�,�tfK<u}���
3w�yb����9�7�Y
a������JSXIU���
d��%�������$��� k=����:����"fiR��[Zdt����t{���AE7�`��6(�M�c������&B�U�s��#Xe�C�jc�H&/-�)*
t��n;u1�I�����v�(VB����/D]�N�)I������h"�Y'�t*gq0cg*J�:D����r���C���"��@,q���>�T(�-o��?���kA.���ZQ�Mc���A��StI[,�3L�����II�����"�����h�W��
�; V�I�Xk�)���`�����N*Tlg~$*���������$��'W5��b����������"e�r��7�w�I��*�����	��M�������(8��j����1"�7�A�����cV=�A����D	��1P|�1��-u��Q���8_�
7����q�P!>y�����+c�E��Xh��E���9]������W���umi�cS����O���	�w$c���H�`����+��Hf��f�QW��Z�6���� ������"�Vy ��u9!���-�>w�C��PYc�i_+w�������.�3U;Pp��_�[x���\V�'�~��}r�.����I�'��o��gV���u;�"m�~j~�}4D)����=�c��D�Y�5K�[�����V����DG�f��Q>g����hP�0���jQ=y�zn�p2���T/1zH��S�����Zt�=:��@^��f.�DL����P���{��>�c�����1Xd��{�NGe*'8
�G���"<�9b���X���r@!A�,��'T�`����������NH����&Q@k�Y�z��~2�C����4.hH���i���CC~(^�w:��� ���ET�k:���T���P�D0_��d�k�&���'J@�t�i%[�/�k�P�_�Q�Gg|�oN2y�G���>2��t	nK�Q!�}���
(�C���T��5'�5i,��KE0s�w�Z���;*�n���������?Jd��p�b�w��"C���`�%J�B����8AG����uRW������NP��T*�����T�W;"����(���q��l�E[$��'����dd������>J�=/��}�)�!�c!H���:��{X�p�;
���nQ2p��l
}=��B��1�������N��b��/j��I&c,��0X�uy�T�K����B����M<S�v�o=N\7�,�3��[17;��?��!�"P�)�X��/q�1�W�����Y�p[��cty�;����F�D�jN-��U������!�����s#(����[�1�P�c�H8�[U�j}����b��,uD������,����>3z�S�u����'j�����W*��Z��]	�b�K��M!y9(�+#-ZLP�$C��c�2�d���#d�q���8�2��
\M=�b��.��}i(H��|��/W!���Vf1�ZQ`a
H��������K��i���\�m��$)1�����������P�� �u6�5�
r7��E_O�`�%�L��a�hu^�����N�t\�R�.�� "���(H�@c?��au���P���5����s��y+������"��3Qq��]+~�b�U�����p��b�0T���b41�f�VU�
E2��y9X�S�����������2��;��eT�p���
C��
���H������28� W���{y�	Ln�>���W���N��=���O����%m�s���;�&0��S����MP�/�-*0iP��~��T�&��_m4��AD$:����lI��q(�2t�@�$�� B2�D�9(��eg�� -�L�`�*��@�^)�{8�$DH����~*��xwL�5�d]:�zx���C�S��O�CR� �By���U6��}D(-�\!��1�*�*�6s�SJN�Qv��d ��f4�
��N�,o�,������i��D���@gt��=��@c�@��nT�7����q�t.�WT��;�=���a��.�+(��.Q�����E��!�Gp2�1�x%Jl�Xf��"�S�\h?i4f;3A��z�(nq5�<�0��e��0��l����8�/G�
B��Q u���<�W�^~��� �9!��-�n���7u4iu�x���W	�����K�~qX?3R=�,$��$�����W����+r�	0�������d�l�!hW��Q�""�!tC5,�u�B\���v*��B�+�D��BT�%��x�'!��I�4��>&
����_��]gL����]����Q*�`�J'D� b�,�V���,���pl�.Eh���Z�8-O2�4��v�LJ�`D�Q0ml]�2�!mQ*����������"��k�9ATW&qm<��B���g_mu.� &����=CH���)�H,����3�&!�H@��V9"�7-�;�MG��o��T���7>~NP�������fn�p��=�z�Z/�f���������z9�'��`h�V��W�U&�]�`�(/U�`���^	/y,q ����?T6�i�I_�M�!"1k`�����8�����g�Sa ����f+���z�9Eo�$�R`J��OgOUt��S�����l��SF�{,=�k� �O�����(�{��@�&���yO]o���j��69��B&5��@�0o���- ��+���U���s�.�w�g��y���_�!0��f��� �,����59K�EV�^�f������CrE����`M-�*���Y��TDP�8��U�b@�B�� ����&�n��cTu���:�*��!sKQ��k���$P���T8Rhk����d,��i�����4�T�c��fC<����GN;�:E[@�	?h�����/�,���������=|A���V�������������`4���������WX�t��|��w���_2���|����fU��+�/��e�[��W�_?�}[}q�����}����8���_���������@m�~�_����N
�������������E���5�3`����|��n����w���W������{��������������0���������<-�������S5�#a������������Q����8c�B*���0��~���gY��~��eX������{!S��j31�����|��������|[�+R���"A����\[r��R]�?
Y_v�������{��TO�����+��O���%{�w?����]����}���y���}������d��,�2�zu����}j�11���_e�z��M�.S�iG���������	G7�������r)��>�� "}g�y��������������Y�oy��[��]-�kB���^v/��=��9�����h�����~V����{]!������	j�?���y����sV��~7P���������_�;Q&���?@nl���������>���qww��������3����������w_�w�O�����/w�/�������&���_��������N���!�����/����������Zh������x*pO~������l������| ����������7?�M��e�Q����������Y�����;�7��s�����_Xi���9:����Z�����_�I{-	�o_wF`z����������'t����p
}<�(w_�y�����Q���t�B0�a��F�o~�UF��g	�3�(��D���Q���!������������R����O�P��AZ�B
|���q�/����R��L;a�3�R�ajr$�_�)���&gb�F���oDL�Q��2+ED!���P���\�&�����~�"s�&y��b���'���Y�4i����"�J�?����#���k��X�O����m<|}~a�x�?����� ����<��6��9��6�(�~��}��~��=����t~ �����<>��*��O_�����+���������Rj��������w�=���4��i�s�#��2�q��N��oS+�l5C����.�������	8�@��5�����@����o��IZy�c!�����x�+��@��rL��b=J��t�;�����{�z�:�sm_�(�����<�{�]S�v��j�����������aw�����4dP����O������(& ����B]_`�
5�`(�����|=8;��g���js�"�q��@��/4)��o?��]�'����=���S��������5�����Gh��k�3��������l�;���d���9�5�DwD����s�+�^��Al3�k�c���?��t�/��}���KJq��OS^��^�X}!�)��y����O��+����%���kjn<`s���/�������f����V��������� n9F��R��[������,����fB����I��s������or��n�P[������������`�������6������X�L)���d�VW���c���$���T�.��.��
4� �;q��x�N�-N���=
z�����p���=��a����*�R8���
���w��"���j�!�2[���]�}��n�zz�=:��G��Z}7^����P�(��3lc�+8)�����~x���!������O������bf\�yUNl�Vs������3nF��Z�:����r*p�\/��Cxf1��������_��gi�n��hpF�	�9�q��q����V'i��s���W��h�Z���dcz��K�m���8�<0�������R^��ev���E�@_�cz�����_�������	�eh�������?n�?9�z��.��Y\�O9_��R�}��)�6!�Pq9��������9������Zd��n��������������1���Mi
=�T++�y��=�����c�3Q�S��y��^�D���������������Qm�u7s�u.���D�~��#����^������pe����D�3��b�n<���L���-rC������Kq7��>��N���r�[Y��f�������7'� �����5����������>���H�����Q#tg��>�W�
�i�n/���3e<��S�������!0k�J9�H ��1�j:^�>zK��I���\�}����_��u�_����t�+�5��-S��7y}�)��-�s����&x=��������a�8�8�����kxs���X~]WN��r���F5�M�������Q�!����,3	R����'H6:>�������u/�MMv�X7(=��������(gQ�-WJi
������t��q��}�beC'���[�e����6�w�{)`��J���4�$wox}�r�_L���sO�\�U��N����.Z���0���5SX����c*��?�@��r�B�����>w�{�<s;���i���|[��{^T%���dBL4�����������%`t-����Kd�2a5OS�!�>b��� ������]�$|L
�y�������0�kO��)�&n0���Y����_��U1d��q�*������U�k_��S^��lLO��h�rGo8�+~�5���V� j��S2�W"/�����/�3�����=���3{��c��S�cF!L��v�j��d����z�&Rf�`���(��c���jp�?�x�Q�-u*�z��}��I��&��`�S���S�)��y&XL�l2mD3�8I/��+���e������d���O��{>�
��V\�i�<�����,e��4������n#��YyR�K��y��V��T,�F����2��s����:�Z}�O�^���>��dl�E@��>(�����?��OL���$�]�P�y���.�]V���R�5��i�(�v,�|]�T;��?Zj����������vUKgF;�����Sa��j��c���d:�k������U��������g�<����j�:����t(�����u��E�_�e����x��������l��<��7�����c��m��l��S�����R'��N����o�{3�������.�5V������_����I������:�s��/��NKu��-<dl��b��A)@Y���>���#�w�M�i:�e�I���~(e��5M��}���6�������R�K��;Cj`�7��%�x��#;���|,���)[WV;YXK-���poR0k���7f���5�>��� �&Wc�XWA�a��o[����{�PZ]���A�l��2=�QlY�����1�s��p���>p{�-/���������mn��J
���V1P�^r"v��a�+�K�O��U�E��B�F�u�l��0R��S� =�n�A��a!��HGumIO$j���,���>4C�V
��gy1��C��������T�����!��ZP�f��L�9�EK%�����9�I6'����}����M�_g�cb+h:W
TD��������5
����XZ��@�����qS�3g����nBj��9��7��ii~�*r4B�R},
�����x=��8lY�A�u�OQ.�*zQ���j��.'����y3]6�8���VV#m��V�$�����p�b���9h��W1=$�F�$su��V��n�|�+7,��|.+�+�������YS�=#��S'�K�����h��5�u���R�x!o�k�����hA��{f�~�U�$�1�`��jd�s�����xk6��^7?��A�u�yK�T4��������4L��R�����]���?N������H7`pbf�w��zq��QDr�����Ll=�	��C	�	n5w��x�E�/j;��O����_F��g�:�:t��-I�7�;�A+����x��xJw;<oxk��_�
�q��P��E9���� �|,\�
�������^)N�"?'�+��B��������"�,���`s	��^�m,�[���P����Q�M6���[y8�bzE���&�w�d��r���j��yS�}F��5��T�s
I�:��-u�m8�9��YD,z�4&z��Y��97��8;�V(o���!���=�mJR�K�����$��?�Pw����<,�b�������F
\eY�i����/O����|��S��������o~'�hx)R�'
Z�����$A"����u�M���#�;7�����u+�P��Q�����:�r�P��W\Y���P���i���Z/�RS��(�S��s�n������:,������#0��+�.{�}	��N�4�����u<���c����v�O6S���q}��bZ�����Y4�k)'Xx�W-L��^�=�e����
�H=SZ�4q�t!|����@������*~Z;�<S�S��s�������r�u�v,b���%��A���j�U���V���=��Y���(����~���(�e7c�i4ak.�2#j��x93f�c��R���g3��z$�$������=���Y���gS�p�54.F��6$1+�U'����=yV�)p�p�!f���kp?f���3������d�������4�ttP��������}���9���x���Ez�������5��M\��$��;�M^I�~���\����
��I�Ph~u���M1W=���9+�����_�����,�b69�����ix�XG�M��.9����v
���A)_���"40^�2wTi_�=��OA�����>���yt��BO�����.�F���C�D|���J�+^b%8���`���.�r>%n^��W��IN�`�>ZAOW��R6���Y&��������5G���a��>�:�.v��������=�6��^�:���VN9ab�����h�wL�|}�A�i>�G�����~�����������9���*�0���]1y9��������Oune�(nx��.�m���#O/��y��Ss��&��x�i��nL2E��L�H�5C�#c���z������xY%L��P������+������/�������h��~�j��Y5���u;>7+2�3��9V���e���E��D�J���<��:�+��W��1r�h��$0wc�i�i��+������������������������Uu��\gD�?���`,�j0��*�/���
{�r���-z\t���F�
i�6P30��j�6k+�}egW�}����<{yE
B_SN�Y����rc$E�7�w\Eylg��a&)b����(<�T��%��44$d�
��f�Y�2+���%��2��f�|(�������!��[����h�����6�-�<(� ���������?Pr�=9�b?����v������,U�7��'��P~�^��B:(bl�`2.���3�^	�G�si��������5xx�|�H�c�`yqC>�K���;���������B�m�!�{a��`@I9$��z���k�UD���.77�CtjO��2X"�L�pG�{�"4�����/��meE\8��\�d�?y  �����0�~��J�,r���@�����".������y�v��V���
�:����x�\V.Rx�I�o�=��y��bO^T�G�_5�r��o���,��
�r��7tm�����J�[���<?*�l�HK���Y$���L�x�%����I�EM�-�'i��u�6���������Zq���3n{;V��-�����R'B\�l0yjKA���8�;��E��_���(9�k�b%:nc���K�6��O��$�`s��NC����uF�gU��m.+G��<���O��2�I��n�LJXy� ���.sf�W��s��sy��O���L���B�'N��f�n����n�N����$��9���:t�P����
��T����$$D���m��ik653� Ia�K�|q�x m�&T9(�V��+5����d��A�L�R��J��m0����9��X����xE��
g}���Z%��+&eCMM1���I��blyM�S�Jv�B�@���O�RW�?v����VW��t�b�q�m�]F�h���b�L��s�G�\�������.<Z0n:�� ���0�$y-���?r�An����-B�k�s��y���|�YNe�����&EyXG��i�q�zv�6�����T���q.#����#���|9x��.���)c����E	�]���.o�MZ�[4��<I��oZt��[f����ujA���U6��Z_�tBqO������4��6��^���M��-����%�
�H�a&���4�_k�1s�T-�����rG���d\�27�����������\��F)}����`+��N#��]�P�yy<��XfTlH2�����V7�>����!���.I�S�c(��.���(����/--�������j��I��pOlSsZ<���
����v��w�������|	2l�pU�f�t9x��1��r#���nQ�	���O��ghc��V~;0�:�Lo�Q����{����i��U��f����]B,�ac�p��=$B6�U�n$a�"��mhfh���R�%&�I2r����'����4��>����I�����8iO��Fw\��R�� FA�F,�4���sZ��T��l�p1����Y�^��\J5���4��tG��L���U��E"��f�(����]���O�N���T
��T��%���<#�	0�9�����J,`F+G���|u��2���1u{���P0����l�P��� J���B�y&d%����t.2��Q��R��4��Yw��=�Ee|��$�q��K�b\z�k81~K�6�����axL���9�c]M��5&*)���t0"�����p�g�]Jp��t�D7W�#x�`�p��^�3r)7o���]W6��O�(�t-F2[���ot���������z����"�����k�����#S/�3S����!�x��8�M�AYhyS���c�o������/c������q���H�����i���7�V2�lw�7LL8�G�m���[	���<�����gT�WY��`����_~�x��mY�!y1/��4��bT?�����i!�-�	!6L(�D��n����;��lVn��\�#������^f�sk��������p{v���|14t.���-���3��-��:��L��P�3�L�����i"������9�_o�h����Q��%K���V���k���]�rA��xB�<]��`���8�(����	���4���h�p�`0�j����r�����{I�S�����ZCgy�WER�o"�%A"����
#k�B�>��|��P�\~:I���ps�����aS���O�pn�{�%���|��h���G{yE��J�!�pv!�!M�H������XT.f|8�@�*j
V�X��:�td�;)�yg��G��<T�	�e�<�
�3��l����H���B@F
��R{���[T(b�%��u�D�3����w�����}�ya�r6l �H��@.�D�n����/e1$=Mot������M1�7���J��8�r)rr��
�'z�(�E+�z����Ze��2�Ia�	���OU|hj�2�N�ar���<�S6C�#}���b�a���K8b<�����b��
5u���,"��[��g��U��!C
x,��x�@X�L�2-�.z�C����iN,�^����T����
�9�^C���!;��#�2UE/�}���wA��U�pH�^L����,�{K����EsQ0���r��"�E%u����V:'e������m��D�2�:8���!��s���,��!
8�q����U�\�{�81��G�^�@�7�xN����b�J�T�"���yw����K(�w��&�:Z�<7��(/<C�)R���S�n��8��3������n�G�~��<�n����d�����
����(�o���d�h�����\Z8�jo��3-#B���eN2XS������ ����D��r�=DCY�\|:����YJ�����1��A�����[%��;�M�;y,w�u�<i�����
d�K�#B�s���(���T/:���>Q�iC}�/��not��X4{4|���M��t���9���q���������F����Ea�
xuM�6��F��.tl����LF�qV1'p��6R�X�5;��""���u�%9��[P����jh��e�+�?b�Xh��8,U
����DmH����9'C����<���S�������������t5b��z�����1�dO3���s�5j��O��k�A�d6/�.�
���%��1�_�.a:�]�y��z��c��M��`�P4O��~}P-E�S�Jb�]��d���+���*���i����[;�'�a�Mx��bY.aH�m*�t��'$���X=��$�����"l����PnY�����^�	�M}3
�<�)9����iP��4]]n4�@��=��[=W��2���"Vs"�_��+����i'{���#B�Jw�@h�?3|���"��_�	�'�~�L
l=���,�@=���c�&O6�S�
 ��[y8�F��Z��0n����U�LZ_)��:����B���$N�u�wI�r��cq��u`ye�4�$Q�[�k��o��b��M�g�U01��_a�}��Ks��^�*�����(�r�U'�,<�Hc/��;����n�h�@F�R�� T}�/��P(!5�����P)�0a��n��"M���)�s9�������9���������O����!��k���({�+5 �G����q�T���C�&�/�}��������f�2��P��n��[0�;o�&t�8`����J�C:��x���7��+?A������e��N�5	�����x�p+������-C�u�qJ�H/I)�W���!��� >����p����6����G�,��nD{tx���rlv��3=&Lc��E�S�����}�g�/w����7t��-�������!��Ni)e_bX9�P(I�j:j�oqZ���s��w2�����Fk��(c�5I�3���t��okH6��3�N�N�M?�
=�UR�F������(dv�M5����f:u������Q\F�1���D@+'"�����G�
�{:�px*,z���]�q��gu���"&nF���]{����6�[H/�O���q}v�����dgd8��#��������E
��Uz��0�U�cu;�#��UE��Le�;�r���Pf�H�����c�T��0"����W~�TiRcc��W�IJ�Q�X��!�S���N��o6����+��U��r����S&�DI�Q���x.N1���Y{<0{3���7�8#��y'�.��D�Km
����
#� K��)�7#�����P����l�����	v���@X1ys���B�?)&�,E^�hV�g�������N��������B�����
y����P��G3B��u'r�c���1���`+ ��v�s������%���y��<����q�� �f�P����}��S���^k������[F�o��
Nb(R8��ymi��B'��b�9q�������>�6��� RV��
�^���I����{������2N���~�
S������O�I��c�:_��D,_\}���/�gx��V+�t.+���w�1��h����mI���Z�]�oi����Q@�24�����:��d�m��N����f<�9���T���#9�K~�#[�Nl������J:����c����?Oj������<���guah%Z{�:#����|S��8
Q���Y��z8)*d�p'��q)%-F�;+��������'�%!�������M�[�B;hq+#���C�G�BCW^������i��{;%Y������u��:��i�93o��-G���v7���l$����^<P�-�/v�2t��J����p$�X�$����d_e�7����1t\�S�cZN��S��$)s���t�����c�PwrxH�3K�U��)����`&�P��p���4��/64~��zhF�	q���t�4*Z��
8%�����*#p����R��9���M��!
C�D��������&�P����b�}�*Ft�m��Bw���$�@����"v
'�$Fp�M��8UY�/7@����A_�W|lY"gK/�^��l#�y�z&?��9��Y��+�z#'���HFX�s�B#�:K����0PlS��
���I��V��l�l����Km���&�C��p��y�U����j�~��/�) u�'�����m�f�{s�eF�����)���z4����cy"!Q��{��;<an_�Iy���s��?����s�����������������"���� bH�j���& �$�l�����ge���js|�3�)���*�`�@�9�J�@6_���G-������X��(����������d�kO�f����f���N���2����k�4
�Z�Y��!�o'S������d��G��t >]9G�)Y��Ul�e�n4�z=A:��H�N�F-��p�UpZ��xv^e�;
�Y�w�)� �Zt�n�]j��X���.d�8S}�uk%x�������M��;��P:L.���P|����`1.�%�h�/	�[���Q��dv����[�������"��>� �M�b��%�B3�8�M��"�cS�w�5g�S���x�����vH��;�,YM�!L$�� =lq���By��<��\;���0B��W����{}��/��K��?P�b�bVw��	�&�t�`x,��2�d�[�1�9�QMC����v�2�}s	,]��Z�VP*�r�w�1���C��Re�XJ��4VY`�E�L�8je|{�i��.�e��8��d�7���pXQ����e#yf_��`�-Nj��,�j�Q^�u+w���%X4�V��;O�9��%�F��I>�[���&}�7�P���EJ$�L~��Wh���Q>�.��I���Y���Fuc����u�X���f�X�<i�++c;_0B�E�t����tr:RP������DE��P��,
����N�0��=T4�y�|�B��(@�Pp�j�����H�aY:^�|�r���c~Q�I�������O�,�K7Q�����oL��:������T��jvm�����4���E�6���B�A�6i�G$���-5RW6�Y��AZn��:�bkY����=qL���,����L�d�  ��2��P���A�p�rv*�<8�j��bkz~bd8�O���?�1Q�������/�/��B<����Cl��8�U�t�
�g5a!A
�S�_�B�,:�P��Q�y�������47O��j��X��9`�����x#�fH�y�_����d��5�{K�BH�Y�{a4�{[��
��,�-H�3��;�M�m��BI���sc�L(����)o���������A���-�QT��+F�.�
��}���%3���&��E,U��h���U�t��
�>
O<��{��������*,�p4�Qa��E�l	�07S!$;"�Ml��Rh��F�"�a(��
E`����AAzE2T����B�mb	0�P�V���w��Q�s��7�W�AeM����r2d��7���o�P���B��9�*|� {L� �-���q������F����	�$�)�\ dqb�)�%~��s%�=�p�5Z��K��&�0��7���\�8d����?�����o�����`p�NGX�jQ�N�����:�����t�s]�Q�,����I.[��U�q�J�G���V��c�C�|j��J�X�^��GF��t�`%�������h��&���n^�CI����`���H�TY�91^��(���eo#�n��<�&��>� ���j��u] ��g�96��
�j�A�a�=J���j[�^Z'(���Qu��W�D^�--���� ��Z�����?����w����B\
kVR��@�G�����I�����Am!��@�	�
������p��$c\�Y'�T�
\_����YjL&@��SS:!;�1n ?���u�]��E�s�wgXL3!�:��.���/�o*�$����B��,X(*��@���[�sg�UGEV��3�.�C��$�U�I�������c�(��X��\&�[�qu�`��i���+M�"2���=Eb~7�����&O<���m�(������s>������7�N5����1�X/s��{$��R
q��8����K�:f.C�<�l�n�=+-d��
mUh�����C�������|->����W�����*� p��2z�bH��2�Hx0���3�;�DQ!�����1�����$Q�O�D1�0���%�P<�(*��cc�Q�60�1�#����~�k���@������-o�H�w)�M�y��)a&��r�QLo��y�d�0?A33�=�	��%�8�il����bv����zF�]:�m�1(����@��1}'!�X�p"w��pT�}���z��o��<�����iS.���S��9{|����d�K���~t8�s0u�c^�\�==�����V@�YP^�G:���a����v���P��+K57.'�*��T���6��6|9dww�������jSW�l���y�i@�~�g��"�$�B�t�Xg�������g]bt�p����}�������8|{�	���������[z�����!�����M�@����~#��x|�?������� xG��o�c�V���Zl�^��5T��_�pWpl�h�z8
� �l�����l��7���������YVk�@p3����{������Oo�������(�bG�Qv����m��2���
R?��$�
VvA�����G�:���{���/F��w�����1rk�r��L����������[���oO7���~������-��=<g���a�U�/����]�Lg�)C��Z+��`8��p����]_6����z��.'lW�8��;��h7[3��m���AP'�����_�fAs�T�:es}�Z:	7����~'���:��,u>ZA��5b���:`��d8p	s�j�����/���qw����)�	���]d�/�����#uz��<>�h�y��=�����tri��S+�����%�?<��o������H�'		pP�����n�\����9������A��1cB���B������P��$T�tT{l�X$�f����.�I@�����[}�=�_���h��/�a���5����Z"�� ��X��}���J	�C�����[:/�a��f��pR������I��/@��Y������ ^�g���W2BXj�>�����o���/�g!��)i�Q�b�x���Z_�Y��g�7�J��i�l��A��%���R�^N�� t�Z�Ki�����X���,�3��� {}�������g����M@/��y�p�?<f7�����(���+v���6@E�x�t��r������m���n���@ph.k��]7\�&b���T���c���M��v� 0k4��2�!�"�j�B������kth��7L����c��Ga���H����+a����yy��:�r�M�����������[Rcb��������$�G5� ����������!��
���w���>CAEh(���)��>GZ�a-����d�q�>U��	�6<�w����p�E�@��H��Y*��^Jp�j�i-���L��.��b�s��u;O��o�1��Ui��E���1�3�u�������
�P0q�G@7�s��\+8(�B"K��!C�f���W���P����)�ef�U��i���giQ�Q�1����h�h]xI�����>�j���o��}[o'���#N�!b�U����H�
K}ZK%/��q�#�6���E)��l/(�" :��s��8+~#�j�A
�[@�B+�<#&<�M���������>Boo��xPrU(�e�����O�~�q����HN��tE������^^�R��w�'�T��(���z_|7j<r��m"��z�{|�8�d����<�����n��P���@V"J
�|�
�����f����h��S���	�>���;zzH�E>0�c�y���Q�-���=�T�gP���8��Q5���%�	���Ba1t�*@�~(�!Z�v�x�H����������S���a��#B�n?pOl�%JH��������|��>�E���kS��o+c�i�!��sy�����B8����c����?'�y�Q4wD{�Vt��Ws��7n�}�V��|��>@�D�t��t�SW�W��mY)!��b��&��m^�`x0!f�Ax�/���8K�������k}��8��<��V:���A�Q�#0�h��t��M��j�m���QN��NA&�rH����n��OD��f���A-(4T�[P���-/�<e���#H�a�����|�����[=�?�=�h����&@���&O�tw�-�	����������D?���T���#tD�����7[��3wm���J<�3�&�l��f�� �]�6a����0�����P)}2��P���@�!F:`�����_u�b-
u.��mO�C�J�BzMF��������?k,Z�������=�I0M
f~HQ��6�u%�G��!q6��is��o��]U�������0�����C�C,0�x�����2'�I��z��9�H�IUz��
*�����o����W~t.�
�Q�U�Z��}k�Db����B+���'�%I������R
x��_s�&S#xL��hI����Y�E��zsbM��C�.�@czTp-�G�IlZ�m�p�	���Q��A��dV�i�8�e����G��9�����'x%�^~\,wX���;��8���r��b���)��y$�S��J��L���5�z`�a�P��M�����C|��A��M���|F�N��z4}k��W�5H^K��M3����8����p�q����T�s:&2@�z��"���F
��S\�Q��T�r.�
�s�P����&w���/;{�YCe��q�d�O��c����0��	����������rx������rG����`G�|�x�����S>7w<�8
~�:(��Gr�\'/W6h��Y�O�����
�q���� ��e��4z���*���[���:�-�����Z�A>p��������".z���J�1f�#tp��9�aN��4S�tI9��Bp�JJa�H0�����w�@��B]1���C��o,G{|�|�!���-:����Y#}T�3�A^~�;�4�^�����h������I�&0�H��� HAu���>��B����od/��|�?th�Q��C[�1 =��7�.�H$PxS:bT�K������W��k�j�(��1����y]�p�n���\-j����q�����#X���j�����)��G�'!OFpd1�k�Rk9������l�C���R�O�����xv�'>S~��6{����-~��A`d^�0�Y	?����a�}lyP���9�1��_.0����.�����*>{M���b������MH<�x(�YEO�����o�:�a��c8������@��B���@^�����r�����2B_(2 %@�����P��_N(@�+��C���`��B'���c�����49`�j��/(������\����(p�+�A��!�}?
��"�0��p,��
�-D�����@���zL��^�c��J����x��m�v1P�E�����=t0<��)N;I������w_T���:��(��b�����!QJ��
I������M����r|���+\������|Y3�N��p0������/2FDr��F��='>��.�����b.D�S]l�UP~({��J^>�x����<:��T�D�<
�!����)���m�Q��������I���?�����8���'s1g��:f�����9�����[7?Y�	Q�v?�yu�L�2���������	i�!g/��to�H(u[�V)��;WA�^2:
r$LUJT�d����o��JL}4-T��j8�L������C�jYV��i ��
f�n+�~�f u����6 A�t���xR,x�����������$\Oc���wA�������\�k�)��y���8T�g���t�|$98�	�o�c���Xpb�RDb��b������fz�)����g�����V5|��+���2$
S���>,b�B��hc���^�3N8F/�m�8`�N'b
�8S���6�nc�� o��rMf����80���K��@��^DXq����x�n��t#��]D:�EY[�>2��44�X�[FS9��Sf�����*����m>�m<��B����3 Z��Q}Z�d�Wc�x^���.�/^1=6�����+GV������~�"���c�r��t���iuX85�����i2T��
5��P6�|�Y���T6&2G���n�Go��(os��<=�����[u+��`+�J8_�1��.������	=��&xam�)�G�����#�)'�����lIWg��  	����e�
{xey,��&R�H�D*��/�!`�4�2u������a������.�2t`r��k��an�N<7:.�@�$��[��
F��"����&��bN���y��2���j���1PH���M*P~�'��}��aw�b���@��D�d��&��O�S�LIU���YU��p��,�����<�F1
�Q�}3�&��2��w���cl,8t��M�T�Y8=j\�z���\�u9V�zuh�s�W��T�j�u#�=���Q-�!]�^��>?|[���A0��
u�g8x�Q����(-���p�'����1:��U��/3���7��0b�}�
�)���L���W�@�o�
��:��F���;��w��rCh
/L���5���t=$/��6[,��YP
}5�������A�VOP�1gv"��3i��~l��|U�W�+�M���So�xrI����-9 �CA����!V
X}1N����Nh!	0W�����^y[��l�$�"� �f��a�
1����67���� D�lRN���m0�zHp����1	�e�}�O���KW]VM�*��`tkS�iN� ���m[��Jm��G(�ti�P�w�^�X�^�Q����s��������N}�-m���3)m�(Zm,e)K���1+�<��9��s4��(oW�'F������ �VY�h�S$e���&!o�y���Yc���
��9�W���jg�kg��C��H�y���R�J���@A
u�,�0��X�*�:0vs��X�����t��k�[`.�
��[���+)I�H�d?�
����r��������8��/i���o`�En��:���:��P6���p���f��Xn��� ��b�f�����)`X/���i���MJ��5��=��������5�*�H�9rt��^��a��_.���� ��c�ed���D������[u�>G����Y���/W_��'��=T�1��
/W���s����\e?�~(��-��g�~4�|����
���O��Y���/���C3U�c�e*b.�A(�;�At��!R�v�`'�T}\�������Z��U���m��`������S���5�}�����=r#I����E���[�<�Ra��JU�U�Z����/�dD���xDf��_7sgOw3����t�FJ�x��������,���s4��v6[E����	o��?��������W��x���yfQ�)c�����AY�Tsl����mU�E�8�V
!���8�`*n������L�W~(T��cL����i�,Q+[����\�	���;�1�2����
?�F\u�.����m�"����3,��`���oC�>ev&G7Vt�f
�%_l)9�m������3byj��y�����6��_h	0�,�2W���-�"����[5p^��R?f�Og�'7��B3�OX��|b�g����!���t����.�
V69��m<�r0�^���Y���[#!�[p)j�-����&q�kU��a��e����c��*�[(����^o��[q0�1�\�l,\�mX���f�jR��a��;�P5,���T�0g��a��
sL�s�����<7�un�e��%�������9�����t1����vr�sc���L�6c��&���rf\Ji3S*��_La��Q~�q�j���`n�8:����� �������m�[��7Bc�<����q=�k"W���NqZ
��m�����b\�i"�\
�{Pq-D��l��n".���U%�&����]�N��[������.��\G��J��a��������7��o��o���ps���L��t��Jzf|}�':p;z�n������u�e���gp�1�_�&tD����d�*3��3��a���R2l9O#�������0/WaC�����^H7��/�0�������k�����
�����7�}������wD4�\����9m����������e�Z��{�G3��77��g0t�DW��� �q��@V���u�6pN���,�/��@���,gOu�
8w�U���m�s�����&�bCWw�b�7�$�����9�g:��1!������%��94���4�����
+s+������m���.�ahs�f�g�~{{u�f{�z���Y��w��0ts�z������i !3�:��mCo��M��c�;=�X���x9�f�0�&������.�z���k$X���Y�-�I��]�Nf4f��Q`m]�������.���a����]�u��z�����l�8��O�"Q���:=8L��xvM7�]�p|o��^�>������mhsu��2t���������+�w��}s��x�����o�d��4��Ry��b-4�����C�i�Je���m���M�fs����Ry8~$��t#@'Q���/;]��XTVw�v{�f�D��W�ursC7����$�T/��m��c(���4���|�C;���Yd�����s����3L��5�F �0B�SK�+��M��E����Y���u4X'XM�?t\����2����O+�LC'6�JY�����/!4���/n�(�X�����������M����H}����U.^�������������o5��O��~��CR��Pm���
�A|���$��
�s��Pm`z�+���W����wk��G�_���ys���-��A ��o�m����_�_1���}u+��J��z��7+�vDR��"Rq'pE���@�o��x����w�;[7s{�z��b��5�Z��W^��?���Ft�7����.��f����o������;��m�k��0�_Sk����-g��"��8���A�x=g�Vt�#��a��������)
�`,��N�]�Q�4���TWYF������x��p�b*n�����������"`/;Z��J�7�����!����m��G����y7���Vz������_�:�&�����r�����m��T�L�8[}����p��5������_O?�\��k�6[����W���=�y�\Z����X�{F�2�~�&>��uDcO_�=�Y �l��U/5b��������W�{Z�:�`j���`��[t�#M��qu��������A=j���T�r�m�f��Q9��~�z?C���
���{���2�\\x�9���:6�!,��Cvh'����p.���1S����.����v6{�S���KU?\�w�0�2�y��qN�l�o���s��m���������MV>�:�`��wx/Z�a�D)�R�c*���h���Sg�X���l
��Xp��
X���^��w�#3i�c�ldHF[�s/�xRA�&�jy�h���@
��0
e��`6l\C�����(D�y�,B�wX8����Gax*Z�8��>�������=��D�3���I�j�V#C�2@��ke,���F
`���W�6M����q^���#�������Y��
����#��l!��������#�~_kl��9���+z8Z'������?���B�S�V���U��d����f_k62�.>�Nq����D��nW)[u��{`��b�H��m�|�l5U�8(��h���*���i�7�����z��������w7n�k��<�M�y,��3c�*��3�N�~�n�{���6�rd�,�j�����a8���}N�o��_�����z�BT��,B���W@8��J�h���	m�����db4�������siU��c1�Z�O����l� ���Wx�]�v�l!���#��$�f�����t�uO�JI��Nt����*<;#���7���$gf��9�P������]p��Y1�|���{ �������	
E�'b��e5k�q�q-s0-L��8W/�E�GVd'�H<���a� ��3���}���@���A�O��d��U�k��Xa �HoKO�Y��Cuo��"���N� ���u�Z4��1�MP�W�:��t�OM`����Q��7Y3�"�2������s?g�6�;}�6��f���K�MC�t�= ���������)�����X�pM�0�x�z� \�bd3 ,�g��Z��k�[Y��r���,��	�����|���p��-���--�dr^��( ���������UP>�,�hB9v��*�������+l�����B��G�s�=o���4z���x��R����[�
j�� �+���9������|?���5.]1���t1��o%G�i�v��3��hj���B�-�-��mYL����u
M�WBr�I�����]�Cs�74�
�Fk��E7� .�S,m��/*����Z�0�`M���&]Vn3�:�	h��i�y�)��c������{��3k�N��~�Y�������M�[x��a���R��ST*���{a�F��L�t���Z�U��?��Q+�����>�/���5�m
b��y����*.z� i��)g���a�"Y��0�:|���c�pD��y���^�-��>x�[�PP?��annd�u����l�
t&��n�VAr�*�-�P*]����=��UV`����A;nh.��:!X)$\�vq(���'�������GU'j%�n'�D�J� �9a�z�j���9r��Ve�o�����K)�"��mp��n��e��t�H�k���R��KY:�:"��2���u�k&O�(�f��}��,W�yO�lL9i�8������e��9���@��O4��P�����^��&l�<��0J��*x9Rz�����*D"f�%I�v��~��P��~0��@�����`
�J����ZvQ�
����������]�����D��pQ��)������yG��H����7��By�DO,Ap��6��2:��|������]��k������+0F��������d���?���C�������<L�{-��sYc��@H�u<�7��U����'�;�7S���D�is��[�J�.�/L�?���93�Y�/u���DI�U�:�`.C�a.pu���7w����4
�]V���������>|&���PP=0��r2M������,�Yy.I?&��7<oxPb�
�ua[�i$2�Y=k���3����Mh��o��3��%��5)��O��J�'CR�Vlk5���� r����.T&z9$��$�x�1t�]�����Z�:i�A�R%-�|
�f���E������7f,�'�
�M/�w�V���	wX�e}y����,�����;P`@��=�B��8S��'9�r3L	��g�m.v��F/����Z��:���nD��
����"-8�<k����J��PqJ����=�nSa�1���]l�m�t)b��ZY��(2K�|b���u�ncu��x.�QnY�����Xq;��}�B~��GP�OH��R�Ma�28�!+Z�,��h����MY�L*�neY��m���T��n��v��wq?Q}a�����9�����,6��.�o���_1	�^�-Y�������{��� �>����j������5�4����%#��J�J5~h�5�2	�CA�c�XM?�@�XOr��V����8�6��e��/AzY+�<5]�:�C%��H�`E$��4F�12�^��8/i~��!
����;)��Uj/�^z���3��Q[�2���q�Af{�#�����R��hR��~�>��|���u
�G'�������6E������M�7^Fr�h������q��a�>�H8�\,7
0QK]�:i����b!��3�1��2�+��3ya�����%�_���$����+sv�Ct
N��Nb��8����4^��e��1)�x���*�|Q^�a��|����C�����s����,s�y9Kha�{6��s[8)a����"fc}����6��wS�`&#�4�`���L�R��a����;
������S�����MT�(��|n;����r���(���?����H�����&{�!�0!h��2py�n]��d��}!��w�,����v�I��6�Sg��,�����F���5=o�]z��F�����r��f���Y��x���v���Q�u�F�\/�=��O��fn`[��0�O���t��Bt��'��N����n�2��z�*���	���.s�
���D�=���\l���E�u���H�"#gw�.x���C�������8��rs�e,���������YA�k�4�
��axf����D���>d�a=~e���N�C*��|<L�[56�4{�,��qL5$�|��d�^w��+t�	��S�*��`Z���~����g������S��i�{pQGb�5��/��S�x�u+>LMn�A]9��x����+�b��VTvP��B
�%G��aUN��kT��e[Fe&{��S�������i�x�Eu��y�Z�#���x#:�������_?��o�#)����A�G�Js����i�z����i�Tv��+A1w��D���l�A��aZ��jz��#|5����^p-�#4��N��Le	e����d�����S�����:����/k�}__-e.m���\����xU���#�����z�I>�������o����.���H�j��4Vn���b�&�
)^�����^(Z����XMF�k)�����)P	v�U�W���m�?�����}���e�lz���dLn����X��uI^���g�!1�q��;
�|�j�X���P�T���R
1�����
=����In8V3hy�#���r�� X+t��AVf��~���](�����#�*�-���UM����&�������)���hr�`]��p]�l��1��&� ��1���,|I���g���:q�N|��,�g~�>yXcY��\8%X����r@5���n�~����+�Kj�I3��%k���-���������1�cmH��5��fy�!<i��$�����k��6�q��9�����V�=^�l];�������
m<�SV�3�C��i�*���������I$�
��EV4r{�
�tj��N������]�
�u[3����?\�lQ�
�jrr����a���1�,Cr+d~t���8,z!��?�7n�>f����.�+LC<���Tg�4!��6P"1�;�@i�nZ�u�`cfT�AkEk&Dj����k�g
���Y4�k!"te��F��;�cS���C`A��+��I�TY
��y����S ���
�	Ksb��y��h"\7g?�R���RM�3a���sb�'
��S���<�Z���n�(���Jp��y-��'6�������Eh�����k�F�������9 �D����&�����Y��]]�
�I�Y��N�������[p��61�^�����E�ovgg.I�y)�4��+\�������Ng09���v�A�&7��K���#��J�.��;��B��:���y�x��E�yV���r" 	BQ)��;�
ptR�����ic�����Yh���F�o*$��X�Q>E\����	,���q� �i�s8Y�)��X��Y�B;��q�+��T���?�����'/��w�<��^�-��v���*�����9"5��������DK{9���e{�Xp^NH��W��k�9�<����ffYc8KjAPKX�Q[��KYiT��?�����6�.���PB;z�S�%h�V=HV����5k�������To�������������B����q��6i�Tq���3�
��c���k�d������Le�y5�X�%b2��T���h�FV�d��c_�����NdV�s ���������T��-O�����,��
�S�mmY
���E��%�&+�P�F�C{�L�_����,pN0�����B�iz�qF�)�T$0�����0nB_�����]flZT�m���#���Bz�������r=�&�s��t���I$s^���X���Z5����=�S�ma�{b���4K:����*I)�6�E��w�<�h*�7�+�qS���z�>����Np'`
��8�2���z��������Nvk���h��Xz�]�L���;�~�3������1{���h�GM�������{]-�p5S��js�?5�f�>R<�+)3=xa�s�O�_,�j���G���Z�*q���3�4u��2���1���&D��y���m���`|�u��?��oLk<�����#@���^.2��6S�����*�4b+�0N�)�<��&:��DO����at�����\F�������0��6�KQ'�[��e�&BNI4�t?��_�18,i��"F�f=�)(?A�Q>�j�is�,lU:	�@��F^l6�D��y�6���r�� 4]����u\ZkSdI��k	�d��NRzxa�c��,H��,#OgD��OH���3812*B�����2�b�&-��V`�q�����,L����@��L�����aT�0�/����l�_dG�\��&#R���a�52Uoe���5�J�4�����N=���y��lnF$
F��R�.��t:�[BHv�H��30
=K#�Pq_��:%����ml�1@��K�����L���. ��#�6�z��>/��SI���h|S�J1X�RaB�1b)�Y�f��D�XY/�����z�Q6�M)Q��l��k�h��>�,
M��M��F�$�!O���0���F��SJ;Y���u�]����~9��������<�����.bAU��h�����HD-:w�����'�S*%c2N#�Bu��X�\��"��1�%M����4Y�j�����99V���H^3��Q0)�e!'��EN�'!V1`�yA���z
���e���]F�M�GM� �Z����e�S����i���+��Q������A�B��/*��B
<��
�i9+����k�����gK�Z�j#�	�
8Q���x�S�%_6���\)�"K���*�wG��3���-�i�Zb����;�E`p*���[�i
��U�	y��������i�$��!��a���m��chG�������-���z�9����?�@,k�1x`���Wi��
����qgB����|���n5�b��*�%HCU�+��]j^�)GW�e�����pE/�G��y�v�i���LI
d�	�a��@/����#�F��4�:(d;�2��	ZgS���T=������u����=�������8z��jGv��U?����(� �k����	<�FrLd�:i���^�� gV.-�&���QO�#X�g��^%�Zq���2u�27�B�)3��Z@�W�|��:�q�!��'3����V��cq��b��WZ�DEh����}�R��V&e�e_=�e�vT��j�m����yUj�0jrB`>�43�b�L�56;��,3����9���yP!TFOf�L����2���\�q�����'�T�@�2��q��%�GY������N����c�~�%�f� U%	z�w�(�W%O�D��;��	�5�S�!�QY��,X�����V4M�k�21�f�N�"c+Brt����m��M��vK#d[����s��Q�\��!/���qtb@:u/29h�k�^�����M�_]���03�o�z?��f��������,5	W�"j`���t���w���A���>0E������4��f�����R����_x�Q�Wwk�v�fQ�`�����f�)��HrM���������P-Rc)��q�[�vlbo]�j�c��5~%T�\9�`��R+Xy�B��5�����w���()&���`9�@���k��'���H:��9�RM�[R"���x�`A���V.�O/���F�C�����;^�U�W+5K�N�A�0�����0R�	��@or��s��GI t���%1~}2YX�L\O�\�eX	��1�+eG�:��E(���i����qDso,�j���<��if��Q�B*�������D���t;������)�fj^FD�fU��C*,��m�j�/��+5]���l��tN�A.����������7����hqhG���_�'���#�m��TY�����C�I�h���VS�o�5��h����*�"K=�K��3���*,�u�C��V_Q^���m���+�w<�i��������P.O9�^��n�"eXPF�f�}�@mx��UZx����h����\=�Ud���Ei�������Z�,�f8�����T���\�yce�9Hmn�p'D�z��N	#"+�����K�x!�%��������"V��U?#c�����b�"�@��R4�me!E�<-H�/^e�"�F�F[�����'Di��.�i$J�q4�'�GL?�~O��������r�P�U�}����v����,\`4�nNB���r�V����I���8��{��8�s���39��[�+�L��9b���/pfC]"�P�*����9��~����#���"F�������P.��2);���s�>�p��A�����i����)�����%�D:�2�@^w��(�]3J�,A�
���5.g�D�>�~]8�8�������kQo�9��SP��j��]jf���pK��\��0GQ����x�����]!�~�1��1b0;�4/M����n�M{rH�r�H��eU�|�j�<���C�5�FR����=�|d,���J���*�`~�&D�h�����]���������C8
�3!��E�O0�l~V��_:a����."X#1c$f ���3�%w�4'���.��B1����\���&��p��0���,C5vP1��kf�.���a�r�!�p�J���� xl�����8���S�Ba��V�����i��C5����U���j�_�`�	���^�$�i�������R������;�z�y���MKT>G�h���%�����(��/;�����X� �BJ����5���(���o&�Y�i`�����8�����	�M�s���jC����iC����F�)���@�d������	=9%r�;��a�H\���p�0�Z� f3���R M��4$��F�-)d���Q(L(`���K���.����B�����gn��j^���EV=���X�S��t4�-#��L�-0�Pe�e#y�N��!�uHXSK�a�}Y)�x}��Y�D-��
�V����+�0'>x����������ju��\WR�~"C������������H!Bhr�H���$p��Pm`(��&�s3�.4P��'L#���:�������9�`�W��#U���r�:��	�����9]P8\aF"��Hs5E2HcMY^m'3b��=�8��5�M�4L��b)����,�]l*u��F:�;8$���d�KUZN�~�B�
;�\f��nxW{
0yQ`�<F���rZ���%���r��fb]g�x}��r^��&�8Y��x�]z���W"S�B��y��U%,�P��Z`8���f�w�����4s:v�G^D�vj}&$�ac]��l�F�����Q6�Y�Y��F}���^e8T@(ME��MW�U4H�����k���h���u���#O4%��q!2��6���W7Z��/�Ry�1c��G)O�>E����uz&��(���=p�t����+vy�4�D{�� T���m`S�(C/�1�*���d�e�26��mMF���"��
S6���T0��-E��O	+�5�]�z�Z�p�����2c�P��Z���������g��X���m����	[�x���?%�������'��o�(����7���)�hX�������C���$�����t�E�Nb���6\5�X�����zl�C�����"t8��C�~�]��j�JF5�(~'�Y��<��X�VLFF���4{�g�5��y}yO�]{��@�>[m�=�n���Q���9>y�������J�B����o���8L��p��7*�fr`Nqy'KK�������"�]'�!�f	|���7"+���vZm�ZoK�y��yvuR����B:� ��T+a����z�t����,��M�A^�P���i�o�\'Q��'��}	#��B��=�R��Z����UN2I�
=3���0�@o����}���`V��@�5��g�o`
�AEn���g�� J���B����oK�6ZWd��� ��^`YSbG/�w����V���xj�#P`����z���#���*�b	=�\4&]��~���`#Z=VC��w�-�n|�#4#V
)V#��Bn����e-e���6Y���)��x��	��5CU�>h�d�H�j�`6lJ�#�7��b�<�%rzc�L����1?��*�3��d�w���T�n�6g���R)��"�|��P�$�.3�W*����j�C��B^`���it���_l6��KWK���T&�������;���eO����\f��z�S=��z���s��S�iT������nAm�����^BW���OE���G>'���r<I��d*J�c_":#*1=�
���)��,N�sGqD[��'�zk��l�6�<I��`�S�xMa�x��&�u���H��;�e 	z����10�����C#Wv�h9��r����fS�j/��LeM�~��N�1�L���H��5H�XGQ�nf���z��)��[]�K'�B'u#�x�+j��������+�4�f��P���R�Df��Y��N���<�ar�R�������T+6c��uN|����,HR�v�%���[�V���#���M����{���i�Vx�t#���O���?T��d�\H��4����[��f�Py��'�AZ9 �C���4����^	�%�dO}p��s�����]���Z��.y���v��2H��tJ!A4b��0� ��se���.���S$O�0K�Ynq��,h[��b?��� �]l������a��x�t�)�c;�&�yL^�<��VTHS:��p��c&w.O��oL��9FV�3��%qu)�v��!��s�Qq�k�6��UW��M[g�8�d�4�;���ttm�R���Z��Y��u��x�iD��:�Efv�L����s�'2b�Fy�!�_��t�IXg/*��1"��^���,$���tfA�FJ/n�a����y�H��W)��&����w��]]��z0X+b���~SX�����qh/DB����J�f���UT�.L��7w7w���������T��y0��Z����%C����F�9D�q��D� �;6��ea�g��f�wJ��xqA�;��jE�x���!�����l�Q���Jwc�O�RO�����V��c������XQ����}�S��_	���B���!����.���@�D��g]�T��{�j���F5�[;;2�3R����u5�,�����PR���E3l�'�I�g����Dfr�����m�<I��&�+�6}
���RMY�"�������g�F�i{�I��FO&L���!S����j�0�2��#�����RM
,C3L^
���V7������L���������'���*�I�R
`���v@�L��q����P�����M�3�I�p�-�i�L���_�2a�cYqu�[����:E�����f���[b�$�9������K�f�F������q��Z�\d���F�/K
�
���v��C��z��M�Ay!�m�E�-����+�Uv�=(#��y���$��%�c�����=v������,+s����kM�^�
`E�S�����m�0��k� 8��1�uj��&�4��td"����f�Z���zk��-@2�9�����������x�&w~��q<��T.=�
9�<C��p�V�e�a����Tv�z2��?C����j
&�`lZ�Z�l�	�a+��U<h�
���)��tq������{"x��'�0��s��
�����]���"_�W�=>w�U��-�
H2DW;u��������s��4��M��'���T�H��C#����A�/�6��/��L�g����DS(�������?(2�VC���1��J�.B���E��P#]��]e�1het=�ye���2����������c��� �u��h�V��3�/���JOn�g#&YM�TF7g1�L��f��$23����vJ> 4����a{n]���uz3�����VON�4�S;���6O�����
Qyv�{�o��P!���'x��G���iN�H�Ih���E���J�)��4�*�7�t]T#
��������|�}��T�$o@��8O����.4���Y����M�����V����-N�r������0��Y�#����
|sI����H\�T9%���	���<kz���x�D�R��iK��^8�dB�r� X� V5���;�[YR�g*8��YS$��t�������)�	����* �$;���C��jk���6��;�\� ����i���;�r�q�`������P�����>�&[;GM�M��A�9�h�<���6���z���6bh��x&�%r��,L/V>���t��������qv���DOV'�u��3�����9�N$'%'\@��~�Y��H@�F���[��*��qB:�PKiF1L�������C&��d��u��Wu�BCz>�����8�����5+��&��AXx&"G�0���r�Of��Jr��@������iT|���z�D3�E�I]�X1�b�4���P�n@�����c�����=����������������C0�������OU�e&�E5��KC��#��DS��`X��)�V���Y9N]\���!���R7���z�������Ta���S-�����o�m�l�����C�|���Ff�}fR�y��	���Rx������k�/���P�Xp��^��v ]\�7�	�5�I3��y�m��2W)e]}�R=���B�P�;��Q�
p���T���r�Z!2e��}@4A��]fTX�a��@��l������ �������]�l�n.��5VH7���C��2�B�f�`a�q�������8v�qA�1��v���0�2��0�<mC7`W�������z��	6�c�� E*S"�����m��z�����T��yO�a�_q�np�B1=��O���0�Bx<|p��Qv�'������D���b�3]2>��x9|������j�_�i*����f�tj���,�P+�/7��u�W�p���3&`����������TS*����P���1B
��9�6�i��g`�KbH�3Ms��.�o��Y��gJ"��f.y�u�V������
����|+��-��A���w��<��w+0%���Z�g����p$E�i�9V��)��c�8�+[��@�kCi]v�AF�,l�s���@cCU������pWd�FfI�Fn�F��=��J��Q������9v�U��Y���(������rm#�^F�1�ch��z����j���@
���Ak2K��!��o�?���%�e����+���xL��6/�8)�*��G?�R������S�Zy�XF���TK$��N�}��	�
��BK����z����T���E<�:s�W�%k���PUf�L��q�F��S8��y�uW�0�V�c�X���$��yr�v�&�@X��v��x��D��ED�Wv:C��FK��.����(���\��l�sx��W���"{��I� 2���Y�:r����k��|�A��"L�q��<
JD4NKt�:D�ca���w[�@����)q���C��h�1])n��l�ED4e��slx���<s��W�d#^H����T,S��*"��� K��;KD�5%`��&��X���z^P��*'��%���I-1���*�����'�4><���TQ��'�#�\0�e�����]i���%Tu\R��XZ�_p��zU��l
��+PU��f�m�$]���FS�3�Q�}Z�1�uw(��;}���]��NL|8��4�G��4��p�����A���d!�aj!2yJ��^&ij)�4E�Ju3Z@��5�F������&2�R�!�J�s�r��B\-�<m�Y�K6cJP�����T)�ld�.�	9v��/�G��l�r��[m��XCZ����������������������q�ta�"��IB`��J�>W��N��E
��p���6�+2��j#��>B�tA�X��@�Vh��X$Z����f�;+e������V�+���Ke'�.)�����������:]�}aD	A\�=�NY�O���N��Z��D�"=� �<'�#+H��O�M��e�Y%�j`E���\}R�{��%�z���&w�:�f���5:c�;*�l%��g��ND��oe��G�=�Kb�����0_koQ�����u'�<4AZ�\j#2��i�"y���Fz���,�98���?��op�!��i�l�o)�u�<_�x����r(R�3z��iB�7���|_
�E��i/��uc�j�4e-7�:�&��Mq��N+�Jyg�~y�,V��l�����X�{��H�G���Y&��p����x/��q����f���s��������+g0����v���7~6�-feX�%��}�-
p�MGn�X����5��RJ��ZY���h#l����xi.�ec�`\��mM����5���=r��-|���[��0U�0��4u(+0��y����Tl@�����q��.#G|�;5p��B��+��/6��	��q�A���S�����L|y3�����Wd �C��n���$���f�D��j��kF��O��D�ZbTF��#�s�
��hf����Fg2TSE�o��
�����h���U5������	�)�\X]�b��`�VA��B#O7����2��u���������l'�z�6��I5��L@&��Mf��t���5b�}T�llJm�[]mCZRm8���fV���xG���4�H[-��x���TS��n��g[������}�m�J?t����TG�����F���;��f���-��Y���O�j� �47ELb��bf3��k����A3�l�����qt��������Y�2�m��u�7"S�<�qp�q��.�����D�m��P�����E5��9�������@��,K��~�
,�����n���hG�P��DI����GtE���������������R�w�0�
��&x����,X�����h�yi��g����Ow@_;K��f����f S��7ix5��]u*tA��0mL=9���R�Y�E�	7��jI�V&1/�x�����jb=�<f&�@���T�������V��6���5(*��i"L��t�?�u
�9���8�jF+������i0Tcy/�Xl���fLt5�NG5�C'�Nv+��y}W��z������.zC��]]�������`F�D�zR��#�h���{�H�V6��N��Q*�C���hY�^]���-pE��E!tuoa��~>���E�v,��&l�&t++�d��]�	���+�Z0�StE�@L5�HN9�8K7Q�\G���>���R;�	�b���E����0��i`e�����x���|qu��E������������p�o�'?���|����(�.�_�\w����O��~��CR�X����Ry�bpN=��:�/~CM �G/���.�~)[��������`��N�������Wo�;��>��������tV��zu	�S��������.�t��g�qdx�z*�Z�8�GY���wMT�U�����������.��,D�S#����o�z%���}�t7aQ"��������3�Yy���|�^������XT5���A[T;!����p �����m�^�����W�|�s=5T^�;��������N��<��K�l��o�n��d��3����y}y���k_��>�����wo|���������3��O��]vc�z*������MZ������wM��������-�����e>.w}('X?�����)g)U2rx/��������_K+�r���}����b�r^@��{>�������O���Pv������{��U'UY������I��h�~�P�W�s��o\^^�������������������������w������������]\����:���[��C[~N��vk��K�uq������pq�TY�r��t��Kvuu(C���p�\��w����s����"{�0�����O�Z�*�������q�s�_X��^�g�o���R�x}�����lU���;L����Won �0�}:$�A����t�w�|������I�Z����n�B����K�kVx=*�jG�g6m�B�I�OD�l�Vj�H�ib��'rU��VT�rC���B�>��P�f��$���]�/�T����!��2������9��I���	������[�'�����[o+�j�������ra�B�_9v��Xu����J`�{Q^�;h�5^V�8��$�����$�����X;���b�}�����s�X�r�#`���b0��V.�"�x��
T��.4*a���u��F�?���=�p7F���n�0��;�w�D2����C��<����z}�� ��������������x�������/��-B��i�mC9��}u�����������o�T��84�O��������%��1������7KF�tSi-���_]�~����(	�$����������F�D'4����K��UD���<C'�|R��0���
����w�<����;j1������w���i��+�]���TY�M�-~��\�� �=���a�1F���~�$�4���
�N.7�kUbBc���Z�w���|�����v�~�!i�
qt7��f�a.���-o�����,�	�o���?8�$3'�$Y�:R^���=���#����/���#�����,B�\S8�=y��������*egqI���
���@��IN���\�9������`��k�?��]��^J�YZ���8P����4I�)��-�Y�U8#���?�qyn�7r����X����;��c`�
~����M���<����{����a.m�VxQ��R`|�=}Kt�W�1�t`��z��1��}�a������[���z�E�����uW�-~��'�q��m�W�����#��.���&�jI�h�v��|�Ek����d-�;@ k�����;�\�i�����j��:��f d�lb�.FZfx1+sLH�>��{NpZ��^1O�4�@���#�H�.�Z_C�$yY��/x0�����.��o4����9i��j�e��`�S`�}W������.����q�9�a4g��A�������	R�/I����V�	�R0�����!���g���m�n,I���Z��Gy�)����m���<��\k��a�)-��hnN�#w�bP�Y��/�Pfx��-7 a�J����W%n ������V~R����:;Gr��2,���(e4��4��j��&^��
C\k�j����XO�6�����X9%��#v&���CyX~H����v��P�~7/�����L�C*�jl��gr����y���^�9��2�OgN����������c�YU�#:F��m#��` �?�<�t
�1�:u#�_���t�'���76/4�,|7��]m=��C��y+�|Sj�K�K~��:|��G�K������:��H�B��^`�G��/�R�2�Ls��vQ�� ���m��tc&%�)�P�Y������G�6*%Tgv��E1�,�f�*��� [yo���Xy���O��A�����&�+�i'�U8`|e���h}��_�$�q"65�7v3o9�9V�X�������|"��i=H��Hb����H��H���Y�-��>��(�k7�B�|��&Irw����Yz'ZR^k���o�
*Pi@��t�$�o�UJ���0�bD�t]�O��(Ae^������;���x�W\��%})KDn�G������M��K�-2����(,�+yy*k�������U�s%�b��A�����!w �X����/C�7n��y _
��ra��92���,�j�7��u
���2���L+�#�54��#s��Q���='�k��,}"��YE���B���-5���a�Y�=����iY��w�w*p[1�A �M=���/Is6���\��4$g�������/5��y����A����!P�7A[�nlRI_�:�;�K6��q{lP������ ���&���Ox�xu'�BqY96�=9��I�����K3���? �
c�&�>u?�'�?y���<���B-�i����u[�KRei�|��+��f�����>R4��>	+��z>__*qt����������4^+>��l��[��pxK�����V��Z���J��/���P\���_�9���*�B[�,��f�.��p���L�F~�u�C�f�����tM�$C�b��<���X[�V� 3�p-��@9�T���0�;�)2�r��=�Z� �-=���PE�i|�B����������)N��'a�U���Wc�%�� '��#�+����2��dB��ltO����?��Y���b��������q��yS�����}����Z���������A)�],��q
���� �Am�P���s�e+*L��<I�bb�n0� 9A��P�LN��V�n<�O��.��;���N�iqx��l}��	�bx�M����������r��0d��������>���5�&�?�*[j&T�����~��t`��IL���F�n;�4��G���������4�!��������s1<<_C�g#�Xc�v+?�!�����]���5������/-q��tS�#����a�O�4��1�G�oO�����F 8L4��HV��a�)�8F�p�h���K�x[�*=wq�u�&���'�E�!��n��Vm�&tY������j�)2��~RI1x����^�w��#�k��Y(��t��{ iSy��������f�l������q�������~
���}	���7���W�Ah��Y���*�,�i;��1����?��<Nco|{�*��&E�r�^��������4Xm��:�@:\�q@\R_K��j�Q�Ri�O��$Et�w�)��*��R��A��H��9*�iaTaT�d���$�5/�7������)`�P6��������������U2�V�j�s?.��=�N�v �|�)��X!bp�#�����	}��X����|a�=���L�����ACLR�*��x�sa��Ui��5���bCV]�#��G��������z�<#+z�7g'cn5�H���
��/K��m�4�|?�'�[�Y���0�R��o�)G=������=�A9�/I$v�(���]S_�����#2��w���YFC������F����Ln���:R�n��_�f�td���-��d�l:h��A=K��������K�/�����K�4*h2m�2��&���R�_�����}��#^N*����K��Z�M�4�����_���
����2�6M���M�I3���1���.u��INKj���z���������LSUX�
uR%������K���`8$��&@����'�a�}&�>�u:*�1�����xN;�p<~��Lu���b,5�����C��K��)�N��e@��W��f4X�P�J,5���IP^U���4V{�TN�����|��?h�GX	��]��I�������@j����&3�>�������]��|�J����B��V�H������P������.�[��0>_�c�YBg�f^��{���������.�Y<jA��c|����d���Vn���<��#��6������y3����|���p�6P�*�{a}�N����o7�f����4����s�
�L|���?y�Xe!�Q�HC,����Hy��Vw��x#�Cc�M� ��:?7r��K���#�OU��?qQS����������@���!�>w���M���q�0K�8���#�wE�mC#,XEg����(W��|�1��+�����FjO-]DS|�S����@�0��$d�����V���CBKE)����=�������Z~t�`bR|cO�(�$)��!j�|��K���������J��������Y���������]g�%��\�������|L��SN��O��hr�QT��3��*(�	A��)�x��nI����Af8?��jS!hc:���~,��c:+���|*"��X&�c�%�Via���OaW�l@^�L��-�W8`����2U�c�"^�AP$�=�HP
H��<M�������cI�'H�G7 G`��4D�e||��<�R����!���G�t6�:"o���������W��P�=��8�B����z���M=�r�4�|��SY���_�W�~����a�nI�w��Z�������������@~��*���	+;�3�"[�>���04(~H\��������n��N��H}�
�0�D]��>�Ip��%C �>%4�'a�u�xa�VT3�*&Re�F��Y��w�D��\�v������b�5�+`4e�Yq��H8'3���s��1�e�W���E�A�}�d�"mp���j�O�jg+�+�\^R�^��j�������]W�=������`)��h���r���YxfJ�������W�������Z
J��O[t��"{�� �H��Q��#tr��t�O=��~k���N�o�TQ�6��!���2p?����?+����o� �"�
�2���������O]`������)^���C��Z���/Tu�������q�yq�tY�ET���U�O+��\�Na�J�r��>6!80UG�e����(��#�{����x�K*fT�g>������5�����������su��-%bk��u��l�7��`��o��r�j!=��Wz_?'��:=���%��1�q�N� /�	��F���M�6�!�[�������by�����$����zH���J��wE����:m�0�nZ\�0�b�8�P�?���������zBq��#]�X�O���F.���Wxy��M�B�3aw4A�6�f\[8�`[���r9��je���+3�4u���(�������s���:��l���5
R����TL�����,�b��������-q�cK�Pvjm�0���P�f��+����Nxx��E&~��k�R��������8�N~Q���0� J��S��c���?ics�0����h��C��H�&N��fb	����Z�������b�S�-*�NL�YR�|u|k�mCo6�F���/��Xw��_�'�c����F�E�����%n�S����	O������K�43�2���T|���������h��f
�nA�"������x���}��%5��_�9�����:m�-5r����Q��������Z��T4)L����xE�VcX���b��	n��'�Z�����z��a���F�i��dp��I	�P�tU���f-��uk���Va$~������#�@@)���X��AC�����Ix9�/�2�	�
�{��r���d*����:��G�n��d��Tn��cT>I�g#���au���d�j?*�Nc]M��L�H�4��'Hk����+j�"��N���k�2g���������\�t�����>��C�2m��;cK���qi�����'-ln�4��}�zKb�CX��T��*��%ruT�>+������&-���j�e�c����^������W-�(���o8��U����R�����1���4�oE�=���x&~R{�F�%���H�VcH(�}���x��T.�Ym��?��s��4uj���[��G��U�f�Z�O\48�F�vN!�����g�]�Wb�x;�;�6��<)l���i>���{`PK',�&0���:����G��4�o���&T���w�{#�X}��1�cP�6�U�j�-���0����������O��/���I���9�M)��X8�0S�8��kF4r�4������������S^!LL�5����ZTO�2^��+�����QX@<�k&�~pb/V���&�&������6)���
w��Z�=,��~l�^���n�,���.���G^�#]v:2����^~�'�=�4M��*4��l����0RC���\Gm^>_�~m�on�������7*��~���T��O�8A��O#�4�x�"�*�&����f�}�6$�\o�m���{��,BgqeGv+<;G���nf<
����n��c���Zv�$������fJ����?4���b��0>��V5FN�Pj�!@ �{t�
�N1���\e'G��;3��D�)�����F�_�.�x-B����D0�+���j�'��j�o���{g�/#t�����8��
�,�p���ch������S;���H��D1�+b�fx5���<��~����k����'����(NkN���������,��Nw`����������x#�K~M��^���Yet�����,z�J]�t�3��.�+|��2/�Y���YUQ�
��N���C���>{�f��i|��bL,�pT]�����w�c��5�&Mj�m��368�Ef�_�9UAu��G��_�,b��g�����
$�%���������KW�b�S��e�R�S�}�1���H���Y�o#��J�q�c�WxD���}5�tI`�Wk�oc�o�7�� �U}n|���cFr��<a�c��
�FVU2#�Rq���i$o�+W�A�}�Z��^�����[��c4>�����:�	�^�08��4�@�V !�+����f�����!$cG�����q��������t�������)�*�c��������3����=��wE�_]���p�O���0�A+qWe��|XT�L�@�.��N_7�k�X 0�=i�����p��*&��KCy*��	p1m����	K�6���b4�j�x@�f�u����%f~|��"�ea�X�"N�P_���gh$�e�#��g�2�~�`���"yB�P@�/�C�9�=�6�77H_���Q���*�3��5���1S�wp�����KuP�G�1$7�B]J��<K/���cB��u����]]�0����k�	�E|]��~���"���+��������Im��T�T.[W>�8���'�������:����;Bv��	�u�K�!tVQ�Gm��j��4aY����G*�I�cN�����M���O���7XF�&�A�*��[��rp,��R�D�~���^����e��RM�w�5���������Z��!��H��>����b_]�xL���Y�W0x,EC����'wG�X��a���y���~�@8g�?a����Z�=)vu�n�b�l������������d���6����#�������P�D��������S1
v��7�q��s).����o���M$L�������R�t���N�J�A�Aa��[^*��?*oh�U�y1d�-��k����A�Y��sH�:{	�$��'�O�m��[����u>a���RP�+�4z����+��)��jq����&&Q�+�������Y��m��������8�G-w8�����,�D�?�^����*�la��Wa����bivg���M����\R;:�>�OM�H��t�>	f���*���X+�<3Z%,��,7�	���A�M]����h=���
%�p��������T"_��Ceb���FG0�C�D*��C9H�<F�]��1I��������c�v�'�TJ��3��rw�D��"�#1���e��O�����$�H<���F����4�?h��8���sx�ge�A���Y*���ET�k�C*��R�Rx������V9��u��%�O�����vl��2"�=����������2��=��"��%�@a�������`���+����=I�,��_�W��P`1������oi��9!�+����L����mi�
�07����=���#-�+�^���
N����\���S/��
SX������������N=Y�y�%�:L��@��N��>����O
^��,���t��ab��i<�-���Zi�m��,�����x�\�	DJ��"���������_]��=���*�-�B,$��m=R�����T��#����� *�:���Fe��|�%���9��
&5tqO���i������[���U�Kc&�9_�������^����
:���m6��bq�{l��N|McP�&�/&��.�OM l@z[�����%�9��>8G�l�Yo?�yS���<���k6�N��H%.���<Q1�0�?�l\*�G:&n:�|}vnA��^�"Kj����T\��	h�Pz�F�W9p��=�{3T!6��"��s�j���Q����X2����=G��*�������c88�y��&G�'�V��.b����[��]M�xvrU��:J(�M����7HZkB9�k�.O�9DPm�F���&����y��������5}����2z�0�$@mm/h�y�T��������,$.����a8���4>�{�>�S�'�,S�ek�_n���FN��
F�|Rj���*���<��
���$��fr���I=!ny��	�E��trL/�����r�5?���s{�j��m������?kK�H��:7W�bB_����%�O�~��,�k9��g��X�������*�?�(�������z�L���2��$[�1�����^��d�&����8����a0���\�����P�U`x(�N�%�^_�vSf��D��7-��3�����N`R�KO5����t��b�&a��-q�E�=x6���ih��y�ceZ�6��Wa�P��]��2��u��r�����N,73�|���4�\4��|�����
�h�>������hD>�p���)�jJ�N�AM�J���&*$A�6���YE+�����<�N[�LV��7��o�#��F<Gb'��w'�o
�F`'��E]F+e:v�jqjj@6F���]�7>l��"{G0
+R�d��L���-�a���L�F�-P��"�����x�v�������~��@�Eo��#�B��v��%Hj�X���O(�w+��K��Zm�{pr�m>M"����+�]�����P[c�Q����\�T�
?u�i�O	w�&T��g�a_>
�X^C�i�]���4
`�
#�-���S1U������.�9K�a��E�����)YL�=�����o�{$�G4���WP��
��=�!x�Hk'oui��De�T([��6|g�\k�=2��%p!�QN�����>���Z���F,D+��L0�����9��������3@�������Z�uY�N`���e���4���������cM����_>v�����
SY@��@|:&�}#��@���������kq����U��������w�K��>��;�7�3�r�����ok�YJUc]C^�;�A0����R#&z6�6_�n�K����k�~8�J��ZO�I�j~.�����=x-L'-)�&����5KL�7��C�[/�z��KzW=��O���3
v|M��@�������j��t�"��,�6�W�~��;h>���K���M*��~s��|�#���LU�� ��C�����K�����yc^s��V%�>{uR�^C���x�6L�KWsj�^�$P�G��}��HjU��T�p'G7�J� 1z�7rk,�?�{���	Dw~�Hx0^G�H(4��w���0x���9�#_$�� ���4�	)6���zt�{jf0�������$�lg�%�s�s�����3�BU�b�,g��H�EI�Dm�<�����
�[����g]���&b40��Xy�������6~��#W�c�`:�B)V�����--U��� �%Cy[�A��0��#�������c-<��c�����Y���L>�	x�5�#iN(�IDP��� x
�@y ��3`��F@	�/��$�L�e&2��J���dV�=��1��1O�`nJ*�p�)�(+���7c_�C�_]c�����yJ��^4�y|���[�x�u�<���E���o�~��QV\��vA?��9K��3�I���7�|/SO����s�{[����~���>�k	�^���K>C"���*^�j/% �m��?��y��#��N����	r"!�L�����2B�Ts^*�3���R���(�-��F>��y*{j
Kz
�����Y7�+���8���~o�]���v�����r�Sg=m�rx�[�?�&��1����wS�R�2�RS����8%������DV�T��s����0���
��i��B��-��oH�h��=�$B�"Iq"R��|0j_��Cv>
���K� LK/!�~L l�������
���O� �)��5�z`/5�J/�,��i"�����pj6e�����)N�}o�v,4�^=���V����'�w,~�������7S���ukC��m^�����4�@J��Y������?����-��Z&�l����]sG���`��������$�Pk���Qw���� A����!�6�;v$�"��T����/���1{�h��a#w�1�����Oe����h���`'�nt.�"��$�,�cD���-�43f�`^�Q���O3P?�b�1�Go����=�l8y��������0���s
<J8�B1���"k�b�j1w���%{0����P����� ,A��Az����U�`[���������1�7��I�U��!\K�mO�Al���d>#�"%��I�i�@(��f4=��'���P���L���w����J��8�������P��j�|(�2� p��<h��0>�C�	�-}l�m��M��DP�� �gd��8����?�����k��&�4
��`j����@���8u�Xj�4�����~U�#(7
�w��y�@M�Q0��"o�^z����V#X
e�^������$�0j�V|[���������-d�&_nW� ���R�uy�9e��$����+.y�8;��$*�
r�VF�A��A�t^�l�c����b�	�����\8_���P�*�o	�iF�g��e}��I��.���E��������|��Z5�3SF��|s= ��O�$�qK�R�
����/�a�[�x����iK��Um-��U�	��k����1�
h�[���5�
��������8%i�4���A��yk~������*�YR�$�k��m����XS��_qR��G��)�� fX���,-����D����������� �X
��$�����`����<
��&\�82������4�ka��=�`�Uw����T��~V�D����C��t/���X!��
Tv�3�y�$�Mr��0������ BR�3�A�j��>!�NY!L0�p�A�h��X��d��
� �Q���P!��'�z�;�-�����Y��>=��1��$������i���\��'ZUi�d�\��R�F��D�2Y SI���d�E��`��?Z�(�	������%7�La���'�����_���;Gg+~,>�_T�#��Ts������3���i7����$[���#�?A�b�M�������������l�8�d{��B,�2�AP4�.�P�'T�g��{�2+��L����`o�
��9�c�y���5}�m��bMj-NUD����A�%����~7�;s,(�@,P�����8�2(�1\I��5�!��ts(��,)v��+�GJ�O^�>6��[=��gq��T��������Oe�.������k����6*_������rnX5�i���Pj�v��������c��i�3���$a����d�b��u*�7p�@����y�D��F��C�3t���~����Z�f�5�}��k����l�sb@�F�����������Z�}S����>��.������+��������"b�=�nSy-����?����T9	vY��HG��Ww�'Tj�u$�q��|1�����G��h���
]���-l�O���1����F[�Z�b��pJ�<�M
���_���;�R{�b�$��a��0�f�+I
��72}��F���c�4V�����y�����.B�x�]��0:>���|aC������)�U2����a
<}U��z�\��X\��U�Nl��b���4i%�b_h<on=`p8�*x��%�D`#�Un
���S��,'�� ��)����B���D�]��OXR�^tc0.�r�N���J?�5(�Ah*�!��TaC7��������o���x�ju_^�fXP$�RM�_�>,bu�y�
;W3�&���f������fy!ukF��I�y�Y��C��7��1b�>C��$�w�4��� c@�lnuE��������y���9)�o(�����]����������Uq%��p��T�`�b��� �l�3��l���X
3�D���&����(C�a8�(X�I�q���~u��gA�W9�3D7i��4���k�]�������0�>iV?����t JkL�O~ni��TR��B���]V�;��}]%�<]]�S6���pM�Q��U�� 6J������| A�\��;���*�k	���~I����\�k75��sq�8XSU�������I�S/�0E+�o�n�I����R�q
���#���QT/�W�7�-�t�
���*�8����Q���6�����b[�z}�J~�����wo��]��:<�9��O�v��*�$s����dY����Aq� �c�j�"�J%��G�|8K�3G������x6_�(�����I# �U,���&���U S
��Z��V@��Y�m	��:������G�N�V!��*c����=��gH-pV�'�ha�I��P��bq��$A����<'�>������n�����h�	��,��B'���5m��H���4��"�8,"g���y��dN�}�K�3Vx�
z JL��o~�AE�_�'(H�)��_�� ��o�wB��e:�����L�4����93@�A���_�f�Z.���@.�i�I�$��T��N[����^����G��7���7�{y�{d��'�+��V���H
uP��tg3-��3=G)����������������5O�(�f�����#k6J���KC3_f
�������u�Ic�LK���=�#?������+rZ���^2��9��K]���#�j'��w���,�
[ X9��Z��8S+��!���Y� ���`��0�C�+�@��DSd)g���}j���4<����o�o>����J�z�	��3��0L 5�gN��I�I	d�j��]k�7��2��S3Gs$*Q��C����>xL��0*������y����`�U���������Z�mu]
����n�|����&GNmJ����]O������Y|��c��fB����D��2.�J���J����KTx&�jm^���]��~�	���.r�����@���[�.�DUM��X��8��S��V��u����0��p���
�N@"1�f�/`����<Pp@$�z'��:L���
t�^�+��@��/#}MvX��Z�=Q6�M�K|a��������[������U�D`[��?�v�:�mfyLB�b��I�}�59���D��Ss4�q4o�������6�k^�HAf8:a$�@ �kOm
���8��u_�����������-���O��w_;���1�������`�����.b�U���5m����]<~#�;�h"Kw{qT�����)3��I`cQ�	��s�v�'R���FP;�/�cU�GJ���u��T��
�
�Uby�N?&�v,���]@�ce1�J�������!�9Y�L������b�61u���N��bx��Oj�������\oLk��L�+����S�{8������{��z���t#��0���/�<������2���A�KTjI���q�*N�+��]OHc�1��}I:R���~�4O[��b�4:�@��j�0d����k�&� S#>M�&����nr,^��m�`�o�DY�����%�CW�����D�~s:EL/tR���C�����'�����@s�z%�}��#T.����T�9���=~���.q#;�	W�����dr�Z�@*F*f�H��r��U�
�g����9H����������aVq�mgeuY_���l3f���Z�x�����(b�<�*���H|�����FjA�y4=���X�
���t�6���S�}x��D@���
��&���t�#[���XEVz�L5jF�P�V��u��cn�Z�����Y������g�0C$*#I���lC���7v3V8"��I{
 Q�f���Bd�M�M���J�!���>���B�4]m r���#������o��u�q�~�y{2%e*��]�t��i�syN����(��[��������@��������"A .;����;}�k�>�\��Zu���+�����;N��H@���	��hCNLf��%NEd��?5�*�X���w��Om��j�t"������������=aM�)l���*�C�L4lm��T��tj�D���X"�C��	Ih��?��c=���<�d\�%��+p���b��Q9f����������B������������n�kT�u���A��_=�s��=���BM���j�������ic�����L�VO�_Y�E��`�<L��[~3���[Bk��/���4�Z4AI"����q�����@]���E�yv�t�&^���	��yu�3���[������������^C���{
T@�K	F��{���!���M������Gm���|:SRj��B�Af^���Wph���eP����H������CQBA����:r����W������w�����uM5"(�fa�/��6���R_��c6r��&��8�@A������y���d��N�:���������C��������:�k����E��ZM��� ����MD����_�W��Ew�_E�w��?��^��8��n�����R~��� ��#��
�t�Ucj�"C3�o��[]+��[@�0 
��/6�0��$�\�Wh_:mz��00�C���T�����5����UR&�Q���b]q���&_�0�IK�\{� �����+�	����)B�it�b�
w.O�eHe����c���RK{CN����Z�7lh��-8� ���_Ee_��*�+f�-Bl�n�n���s&������d��p�/M�6�����f��~������+D�,���TzfI�hZY��fIJ��0B������!X��������"w_G���3	��U�t���c�������;K2����$�� ��<_�8;�$���:z4YV��@�j7'����}�lF5�W|���nM���}��#����[�C"�d�H�8�7��l��Asl�rq���=���@�?E"���h�ySPB��X�E�y�t������`q�#�k�|1a����a���o��5����1�o���Y2�&]���rK���������������4��S���w��M�g��h�#%�~�8/�cW�z]����D
r�`b@��N��lq*���m%*yr����M-DF4��c�`�~�Fn����L���?ozc!]���<���-U\I������ev��	4��qdL62��U�!����?D}�SCm���y�'���4;�������>
~����{f�\�a�:� �����>��9�8���U�����$���<�K�T4co��fNZ�|����ZEB�`2�a|�N��?������i��
��s%*�C�����|w(g���"l������������o&�]*�?�4���[*D��y���y�d�y���������x�N.;��!�WA�5���������Q'%��F��[��np�~���>H�����m�2�
�d������Q���>��d�	�[�z<���E<t� [��I,����� `�	�Z�@O��]RD�8�kMl�;q����c�e����BE��V%;�N���}\mD��$D�Z���t(j��c��l��#F�?������9s=
tb�y������P��>6��0�o�����������K��b��	M^TE�}>LLp��"�K��b���k�)Ce��h�'��
����rj�����y;��q?�k���~�|����nl
��2HlPV�r��@X���`\1����OW��h�,6�?yg�~�W@x�V�!�S�O�g�9	?^�<Ig$h��#�Y�k�?���w��}��z�Y�@�;v�����������LIE�~����(����,���g�T��B]������rR�#H��6���l}�#��K�+��Gv���(G�8�k"����J['9F�Fu����>d@5�2��B\����c�7���n���G�j(p�(w��R������������5%2V��V�b�~�{��J���1�c�Q=R�1{s���'Hg�-�Z;Iu��������{s�����b����6K�-T�>�Z�*m%]Q�5%���l�S�%������ �4n�)xBb�Z8k�����q���n����W���2S#1�SSdQ\8�'>�Ol1���f�g�]���"��5$Z�s��fj09�O����Q4��g�i<q������_������2�P�fU�^z:������O��C��</�{�"<��l���>�S����P-�����vW�2i2;!<�3�\u� ��J�������2J|���]SQ���Yk���i��L���h������7��������W�W�Rh@xq��m�1)��Y�r�E��FR���.@jD�<�w��'�m����+}|y���1(;vM����a{b��t�3a�@��>����]T_�:� ��A�N5�����?z��P~ x6r�:�Io�p����)�'	����s=oH�lV;��*���"�}�N�/��I��s������J$�:��V�x��`����B��d<��c�c<�?�Wk���#/3�b�����5y�9��k���ZZ�y=���2�Z��{g���a`��1����S���,�I���:f�R��.��c�wLn��a�0]k��eu	����K� �V����9���E�_
�&4����@a��wM:	b)���Au?���i�G!�G���o�K\�J��eU�tKnK��9E�[P, .&�t�}���9����)��r���?�%$\�is�(n��<�C;T�6H	lN���"n��B+��4��W>�l���5M��"Gt,|��i_	~p��o2�����c�F]P�L��~�(O����R�|�O�h�J��cLw�����J4�f������XdQ5��d����2uCi��?�W���}�7�gYm�T; X�� |��oo�y

Xn�+r$e�.��������g��uW�0~L�j���������R'a��I#x?�{��R�.�E�&C<u�
j����4:���������FMQ�O#�g��QLIY��i���d���Y���C�
=�t�\���G�pd��*����(?�������
%�[���V��3��`�<�*z����!����L�>���:�B1rv0��$��s�!���I%�!U<�����=D2���*��)���
��I��1��P�nI"�Lt7B�
x�Fu��AOD���D[BI��)�\�XJ�+�7���K�u�BY��m/%����:�'b|R�a��J,�g��RW+���6�Sh��g""�J���T`�D�[�Z�S�)ZU��I���!��^
��b�R~	�8N"�������RV[z��]-?������RQx��q�Q����a�w:,G���.��`��9�]�Q��P���J+Gp2t0�K�iO_��w���4���A���}3�&��s��#�����2�}�sb���'�
%��'����AqAmd�n���n�H�;�S���pLl�N�J�.N��V����0p�gVJNG)��.�Ek�O���5�9��.��l�BN=�+y1�M�����9P�U�*�7���'���p8��O����)��'�"�T��(�l�����ia�����\f2`������T��PO}����6<��S'�V��t�*�����W����q�����`�i��7j2�%�
�����W�5��������yg=7�d��+��Y����Z����ZT&�W��A%��EQ}-*�)�Xg���^�����Qx|�E[�S����7w5�|��}.�@��/��c��mYwi�F2���~�Y>�
lB<r�!�kyt�9��E�5dQm�3Y�HdX���>}��-�����u�5����*���0_�|7����j���Nb~�����'����.����&�����`��N?��A/��<��d6hp�����0�_�Ngbq��!;��v��Z���5���c�<
���xrA�x��@\��a,��I(���<�%	���&w�:.�������T�NLF��"�������:�@����)-��������4Zd?����&�.d���J��=�j�4�dw������eL��|�"|Zes���Z��.�j�����a_-����L�W���v���T?k�e`�Eyf�����J�pw�O��0!3���[��)5��U�x����F/5��_��Oz�l�����==���������D�-�do��n���=F����M���S�j����U���b����1�}�}FO�4�a|"Q@|��4N�m��:qr�������LG�z��F��yQ�,+L>(v�nE���^z�cl!Z��ml!�:��sN#�j*y�3�h8
�������<��<}� �!?����x��Q����������:���]_��$����M=����M�"��P���MR�=������ >�zK�tbn?1B�?�i��3�2|�j:��i,����_���T<��,qv����i���2�K��E�T��e���b���?�/���e �E?sa1x&����2�u-~����3��"��

��t�����EF����0�����r�yCb� #����]���5Y|����U��K���6����$�4a�*X�������q����
;kn�Fv
-�������G�����u' ��a��#���C���y�*Y~$d!-��c�0������K��Bh�j��M��A�W��.�gq����i<)�x�B9�?���K_�&i|�����	�bO�5t)���j��:�������e���YfJ�e���rD�Vh9�v�-�,�>~@n�_:�����TS/�����H��
]mb��F���+��rQ�S����5jj4�J?�a�����q����� ;���`�t�"m������A�0����?��q+���?OG!N�N���>�YC���������..�UOs��bU4��O!�a����n[�-g F���0��2a��W
��p�n��@;�%�z��B��b�=-G��e�.��h�;`�,�b�h��� ������U������sM��Z�l�pt)#��*����s����_E��0wKh����._�	TH$��Z����&��������lIy�h���Q����`k���P�;�5}�@hU))���V�,m��-�!O��Z�iNip����c���#{?!3��xx�9�	^s��0�'�(/���^��;���Q; C�lu9w�n�������uE
������������������Y� 8&)t�)Sv��"<G�]��H^�K� ��c�V�36��)�&��~	B;� (��t�@r?2
����p��N��E��_���9o	�C�|qq$Z�. `
�����(�A����OHh����i�"��(��98M�z
D��T������Z
�������Gu��,	��e)ZIz��N�K���[�A5������4r���*J��jc��=�2>����nH��3����"2�L1'�r�����c,��|�Hi[]���k����>�q�TJ(wi��#$x�aC8n,��~`�[�xk����S��$w%�����H�p/�4�t����������^B:d���I�RF�XJ)[w��UAE�|��k|�A&K:����Q:>�O@�	&���Nno%�������fK��������I^��u�i��}�4�������Y	��2������N#,M!��^6���Al����oT1[�����C�4)�C��.�m��3~�kF�y�\��<c#���]�M��V�Eq���)h�q��I�z:]o�$!����O}�\y���)��K4��?����^��y��I@��`j%@���5Ab$�a����H8��0�E��
�<��"��S
�p;��s���8�A5���?�]2r���?��&
�l�,��c�7�D�d��C����$P��9!h�U���n.B��:����}������lub;v�3���U�*C�;
{���� ��f���&�g���\�Jy(etT�4q?D��H���;}��q����z	�q�k����%9r�e
)7�W��%����i�t��Q��\�!lM���o��$uP7p
��C-qM^�x�4+Ybo�l��
X�{/��7��z!��"U����j$�w1:eECP����\������Y�01�����^��&���5-*�p'��Q��$�:���\D�_�J��m�L��8_��!�%��QR�M&.�@���J��4�(���/d2~O5��@�0�
�3����4��m��'�'m/��P|�[Kr'���D;\�5����H]�6[rc(}]�����M�"����Q�0�IT��&�`�hN��;����H�d��GZojZ�E@��������� �^B�7P�L�b�R;9�v��?�v�<���w�](�����mw�?��.�cR�b�p�7j��,4���*�{��,���<s�|H����-ob
���(e#�V:���*m�u���f��o�.�l�1�2���r��I���GJ���; ;�����}3�^��Ut|��+�4��0�
������s��-wb?|�C�DT�������[N�v����Y���,KF��?�����<�	G�p��^`b&F�X���n�*����b�����)��������bD��)M@'�#�E��0O���z��pw���	7�c����������EYE�;�<�3Cl�B��q.oH<k�G��8b��}���d�`������2������@��|�R�m1�\�\1������<W���3���|q�/>�S�ye?��u	�����N�N�������T�"��4�$�W�D�w�Y����!6^���S��(k�F�%
r.�0�X�����,��H�h��do<%)<�	� ��;���W#�fL�^�D������R�����B�+���.@
�v�7s_��S�7���\�J�]��I�<��*@�^H&7�E
��&s\������~,F�l����#��F��������K�z�O2���5�O��`��II�Nd\C<�'�
��;�-/,�qO��E!5T�
���,�G�N�Bd�=��RM�M��m��m�Eui��l�`�J�u���� d�+�f��	���Y�R�6���9��E�{v�eo��]v�Vt0�(����I��rI��e`K�[��(����0%fz���l�����,��ivS���0w�/;�g��t�p�t]�	3_��^d�����7B'����d��"I|��P"��'F��s==��?�
�� �i������Y:%�5����l��y��1�'$\`����)��g�`��������L�TG;��Cy8�8E�l��En$�N��%!M����J&�0��o�a��UxP��Ad������z(��I;y/�aE�6���c��D��dH�;P�6�3?�{;4�������}�y�.������n����r���G-���]�%���AD��'���7�����dbT��O��q����^J�����I�&�*  55�\���M�bQ/�����������i�]��N������t�.�Y��m�]1�l��3�(��� ���T���Qv)�h9I
�N'�TCt��r%B��U����3=6�9�\�'�E�W�t��SGyC����'���-IL�2�@�G4/����J��������{�����]�n�y=����!|�P�F��j
��z�����O�9�`
y
A��V���T&��2��Ht���U��jzw�#Mu�P�����B�{ka��y��`H�5L��*k2:����D8����=[������*!�Im������M�i���
��D2�
���]5���������*�P2��y��
J�GI�V�Qu�����^����MU���/!1��c(���(@��\6��e*K%������[����������T�y�J(�,���E�s�����1-Q��iW����TI74�lu��T�V�ox1�>
J7u�a�Z�Nm'��Y�D������0�!����In�E�2	����X��e���H�q��7?�i5�u2/4���f��S���JetR�������D}��&�\EA�Y8�(6�p���vRE	n������]l��.a��/&yA����[]���2�����|nk9!�����:%��;����c���V�C+������<	0��7RB`x��]9��n�ZD$�V��?�4X>�c�N!\���H������������������C�UK�( Ja#�o�IrP�r���f,b�N�r�}Uo������nRq�)-;�:~ b=e�����me`	1@�E��Cf�U�ir��D��R�p��r���-����c��!$%X{��eM�)�;Q^���IaB[�R=�A	����|�#�%�b=
��D��>����{�#����x|������L[`F]���4�7�'���y�]y,s&�a_����x������g[x�i��5mT#o���F���%#;�����Q^�^Q�.��)����R�y����tv0b����8'l�@�� ���^�,���%RB���g�v_uw&������]��e�P����D�
q���T�NAgk����Y���O�6]Q�|��G�~��ar���q�����$�JtX�$8���#���)���8+p\�
I�7�1�����,�,"L=
���.(�\P��J�&�A�OU������oS�!��2��&F��u��{�������H}�"G-��1#C�w#��o���bNP�[��~�EU�����gy����@o���$Vh��,�:~����*q9/'Sa��I����Y
���\8By����N�2�/g����S�=�����p��F+q):�+e"�8���	���6QYT�����ah��m�����/{u�dQ�������_2�e�q{���k�����I,�?6#(�
���*�D�~����>J���#.�l�����Q
o�6s?&nF&���,��.]��?=:Bo��y��|����W�lA��I�+�d���&�))�J�����_>�)������p&�(~;��P����������U�e�&��&�S���g�����D������-��}����p������
 <D�L���<�?9ux��+ZRyr�����-�\dm��!�d���L,�����nhT����{.	X� �L��1V�qma�!C.:)�7aQ��?Q���(��NyB�'��Z��y��P��!<�����)x ��bXA��I�<i�����X�b�4c�@�(�k[����E���naaW�D��%[��nW����Q�"Fuu"[��W�����cf�?����`�S���m���Gi&
r��\�u��jo&�C�Qn��[b��Qv|7"�!!@6K�Q#�)k�����&�����y=���c+NZ7d�b�8��1g����A!��j����g�>��Y�cXZ�h����x��>
#��=�3��E���P�pm�Y���w���h�A�����$�^��"��W�fQM��@h�+b��T]Q_F�?�]8��������\�C��V��U#]����ZE3aw�p(�}�:o�GBHkf��'@�����@��H��e����m��v���u���f�mQ�����l& ������f���Q ��;�+�L�4b�M�B�=�=I�2`'B�#���D�}�g3B�t�F��c���tM^r�O�`Q��h���<�(M[������*�~[e��N��B�-$�(�,+��=��	h��?� ��:X�6��F��V��|}/���	��e���k�;L�
�JD�]^����������I�&3u��x8�"�����<�:�����MX�"�,� +Qdn�����q.Q���Uq�m��b�C����|?k�h�K�1�1y��T�
�U��57B�N
��/����{�f�`_�����1��"���.Z�*��i!eo\<�	�3P{om�/>^9��(q�������0-�3#]�������1I����I��9�M}RE2X
�8�O�����?��=��(z�����@���/-h���;�j��h�
�YsA����&j�s����Q���H�?�����&����N��D��b���*Z���"fa����"������!�������&��c��8��
���_�B�C����3�	�i(�E�����n*G����8-@/.��1����s2���@��Rz���GU~z�sN=�R�7�x��o��A�
<��Z����#����{(�4�j��{)n��.��������SmF�u� }��7������O�LI3� �C�5:�`_n������;L��ik������R@)�����d ����L��!c���p#{M�t�%��$B2�#���`
��F�?gy���c�#$�~U��uCx��EZ}��=b*�R��:�:������`.6��0h����5�O3K��������9pS��G=��%�m2������9`���O�v?r@9$N���4ebv����M�w�l`�e6h�8/k��R�x�`IM��Av�*���d�����<}�����E
J��oR�����o����aP�M��o�:A�}����?�K&L@+N�.�,G.�����
��FU��*�(c=����%���/������"w%�v��V��Hn3o�p��W��u��?�'��;M�G3����D����(�G�x������
�/��e�����c�Z��2ET�(��G����@�����/�L
����2�3�_���4�� 8���<�(����L��L������������)���:����h��QH�-�\S���n�����
"��T7��m���E����)�]�#kG��I����$���*TW��$H�Y�����A���bR%�h~��W�|q���W3��A�W��qN �(Z�O��n�QX���	TrU�^����kcw�^��YC����������m�%�G�����`�6���
���G���1�	��0�h2�����09�W�DU;�����M�~���J$�%���F��)�����F@��`��cK ���*�7sA�N.k�mM�AJ�2��b�� �K�X��x�wC�Gd�5���Om����H{�
�,���S6>:I����b>|�n2�!QC��������[��s�_��N�pX���*��T$�3�*���ye��\���H� ��a�B�8"V7�$��D��ll��3?��Q��C�N�?�i���%�<��0��J����(����:H�>[k�5�����7����P��nMU�����x��/H9����*�E��N&Et]�E�����BaX9������_����_�Q����.#���?�)��O?p����XuN]/C�2*?��h�x�D��w��Rj�Q�L��(qjv�x�i�}�-PF�����"+��r�G)~�������T��l��f	S������e<Rz��F��\�Ptguz���< �]��i��/Kc�4�p����N���JS��"�N�']�
�E
+��]*JMV~��B9���h���.���v�;yP����eWd���@���I�Y����B��.z��h��:���z*�$�m�������_^����N�g�������	�4�[x�{a��(:������C-<m���-��4���n�R�f'�U%L2�D|0���hW�EM���K���'�����fX�U�uc]���?Ocj���g��d&����"�E0{��u����������Z=�����=��!G^�?6�>��!A�S�����.-�K��Jwn)�N������L���m����x���n$��X���i�G���R`a�,��b��D������@��;ch��UG)D�G�{�&*�W`r��I,��������)P #�X��R>-~�������ZBD��4�q!��/s��H8Tg�YV���������:���#��x(6�e���������������U���twv�����q�
�:��2���x�^��x��	���ZH3%{BA{;�l�h��,:U��z�:*�����F���	����w�n^&���e�)��N�������y����T�q��[:�X�Q�4?�����C�';�P���8uqa?��t��m7�?zs����7�����<y�����[ueB��\�'x0�)RV�eL^���vc�1��o|4p�""���D@��QK�V0�x�1������7m���� 1]�kYG�T�������E�Pj�����f��`s��8VY
!8�"��KD@��W�;TOo^�>�]��e���WOX'�SX�Kr$�q���[���D+*/�VO����B���{an�!�U�����U�F>��X�r"�\��)���x�Mg�j�,���ec&�&&�#����]TK��$4��&�y
�{�%�_R��w'�����k��
�Pz!���AsMg���0MEG���P8�v��::�QW��x�tOER��*���
�#�/�^i��u��]�G�'�R�`�R�@d���jH���[�C ��V����a%nv�>�����K��@�g��'4=����d)<f,a�������89p�S�m���b"��M�E�b�22��)�J6�{s�`Z�B�s�2n{a��!���I-��
F�g�XRk�iE��~����@1����!���E���e�����_����t"�[��/���<*m-�}��fa��
� ���Q ��@���0�����a��� �D��H���4����9�%���!��m-I�r<u�����X,u7J������j zU��Q&Z�S��R����r�+��~L`L=�'��}
$8.�M���&��r9���3������KkpM���FT��-��n�"���M����l�<@A!��(��4���}n����v�~���*���)�_���8�*�#An��9�4$���,��]�M��p�D����kQj���r:��kZq0q�2���\&�Yf/���
W1?��U�0����
n{zC����v�P �v&{��<�fJHhl�Tc��d����Ei�Z7+�5r�!-��QF�@����.�]bF������713q����,�#L�=Q�>N���,��l��q�(��t@���������&#o��A����Z�G�!�V�^�J�%g�p8���7jZ��b�������G�X�mc�%$����I*p���6�S$�iI�;��%�v�:��8y#�VQ%;��!�KUn�B]��n�)2D��wvMp�������t�����|�D���=wh�����qGK"�H���-�"D���j�4h���h�\���P�l�r�KYT��BeEo5��<{���b�d�iE!���%�%��#v`��.[/����t����M��J"2E��"w���������
8�&�P��z���b�sU_> .�\`ht2�o+a��V<|�
�1�U�n��=���
{el����Fq�����p;���4�W�2��������m���Ol�S�e�R��Y�����n��j!�7������D8���H�[UsN��\)�l�VCzr��#��s�,�m�@A��(���
���>l�Ha���|���8����u�)��m�|���||��Y�J��mA�������b�{����x(��N�7)�b���
q�RC��iI�Y#�
	���9� �$����e/#�x;������_>�)���e��G�� ��"�u.�@ne:���2����K����4�!���l�
��Y�$$�M��@0������q
e���K����4���,��N���Tn/�o�O��/7>��p��!lAzy��/���Q99`��Y����/�z{U����h8y�6��l�,�O5M���<.������F[��� (����8�q�� �}���T3���xI2�^��d,�D��v��R���' ��'P/�����#�Y7DW��-��f�\��@�-�$����w7�#P}em'%��)����H����8(�>��9vN�����8� y
�#����,U[�"��<�Fo��������v<,K���,US�W���� �r?c�$�|�H�RI�N�uq���q�Vdq����D��.�C=k���7�*�7J��I)���(�c���TqDp�%�/��r�G#�������3��4��S��e?^W�����
&�����C\O�*���&�u�-�{�k�.�Ux�J��j�<����ez�4�N����q������5�<�"�)��3:x��q�^.�	H�Ty7U��������?�� �����a,i������t�f0��e+5��H@���(_S�`�tL���Y4��r�"������Q~�T����[�?����T��R�Wm�@%R[���9��f�Mc��
��Q�#�6�$��u�����N����KKK�$e�bC�����J���!�)�����U�?����D?����
Z:�A&=���K�3��{�7k��Ne]���C��f@��lh��#_���I2oRP�"��3D������s����T	��A�v�x�����(��+Y{�����<�VtQ�h�����f��s�w �hmS�����
�������P>����MEg�0�A�����e��J[�6M�������>�Xgcf����8�7I~4��' �'�4��M����'�)�������(��,�RQ1 �����`W���}o��T��������x�f+�y�V�C"�|��B��1"���}9	�e!H��!�Y�p�U���Y�w�aE���f��nc�]�����u�D�$�����#�t-t�>����7�x-��~5�g���e���5b�����[}?��r�"�����8�;�������]�h4�el<��T��6}��������]cg��tO0R]2b�����V!�^�������T����,te�D�B��	�r,��������E�d8�A�
��
M���W��[�aN�"3�����h;����[�U�R��B�����W�#�J6J����?Zz���	��_���$��3�S�k���/��_�}�?P,�������/�\���u������"naT`T��Js�@��<
@�����4T�T�	R�F"P!_~H�L

�F���wx.��tw;�J��O%`c4���*C����F��[F�0�u�F�npH<�O�Z��7�CIXrG�T(
?T����G��� �s��th���4����y���L&��F�:m��Bf,`�"�YrD�p��	Xn�
�b[�:��us8������(�X#�3���j���1#!x��p��{y��qp��������F�)���1>��������c�_���_���M���3MS�K���?F��E�w�Bi��	i�J�JF|�)�E���SF�iF�H�������9��
��B�@��D)O`-A�K�\�����?������F`(s4����/��;i�f�����<iI����nh^o��4�O��Td�����E9}&^�0-�P0����>.��Y0A&r�(�T�1:# 8��H�� o�� �X��?a��������e`i�����<cho�� ��{�	2��at��U�P�s�a���d��}��s�g��l2n���xO+�]7+ I���G�.����'%������az�i$S��,{3F~��m�#:��J��{��%��?��#������	����#�d5\��AC-��|�q������Y���r�Z���
:���,�fqE`��LU�#hY!a^���i@T�`��o���Z��@O �Qw�D{��X���k�G.�h��\O�}�����Xcct_�8�(vP�\@�}��}�Ec��]�X��0�?O�9��2*{K���G��B1Yq��H��.�o��-�66l��rG��tJ�m���;���m�/�W #pQ������}�����E�Swc����C���}����r
"��f���T����o\��
U�^^���A��U����8�;u�a�����
�X�W��A�H��l��,����	4g�s���>�KV���E
��M�~���8;�h8�
�}��]R�������1�\D:�j��R6_��i�x���1��������N�����R�h�UC�b�����+��<�M�b��wSfO�.�LSB\(L	TX2E��,Pi���t&�Tw0D�v��nQH����d(�e�����.#t�.��]-��a�`���0xEX����x�%-�K& �`�*����%(f������U��C	�8Ai~T���mk9�	E]"�%!���W�0���>����*?%_�T��A�)�t .���aPa�v�h5z�b�uUU���U�R�1�8�J�K-u��7c�p���/3C~�r��O��wk���s�x��y�-����<�X�t�a\�O����������|3�x����4��'�r�|o����BT]g�s�m�f��I���H���=p������y�~�X��T�;� ��h>�d�h���G�]��DY���y��x��HW��<�qg�
����+�_~��k���!�tb5 �$3j���"a�M9xJ&s�t�Iy����DH(�������w�����,�Z"��r��H`�v�K��f���w����J-g������c������DT������Pxir?a:?���=���^�����hq���(�A��l��+��DF����a����]:��:�e�15`��'��9�&��%�"m~�z8L��ZBMqZh�Ra���U@<��&��������I��v�_u��)�*��vp��5JA��b����>9�����l�H����2W�R�T�S-N6
w��O�����>g��`����'��'j��D���,+�h���X�]k��mV`����0�2`�+��h�m�0��!&�Ngc
�����`C���Q�<=���H������`_u�n:QPB<>�}����&���������A�����C@r/�eU��o"��\�29��#�������]Q��j#2eGz@��<
�<�ui���~%�n��ql|�H��Q�Gz`/>M"����H���V���k#�E���u����Z����"�/��_���q����f��=��m���[�k�HO����7�8��^�����Z��#��f/�4+Sn�2��p��K��w����c��d!��8�	�28���\(��.����!��-��Z�\jPR����2���J�J9� Es��N���D"! ����
;�\�}��b8k'�``�3���,�S.R�	�V
j�kI
Q�t�G����&�
J^Cq�}���Y�t��-E�#��U*�4C���)P6�)���C�&M��'��J������q��_x������a����g��)����w�	��Q�hg��\�@�e&J����C���%7�1�����bm�������n�9�@������y�t��${E�J�0�1�<6Hjm�`Q5""�X4MZ;ECFSp��+�Rn�o���dOH:�(���#M2���_����@2��(xn	t��������E�{��O�����q64���:M�4�X�������J���b���2��x����	���2	(���K�������?E���p��/��� `�N��N�$}����������q���:e��4��E�zq��-�m���1��P`w��/�`�S��*&��!�p�a,9[s���%�H�����/]���,�X�B�O��Ks����Az9���R�w���A��w�#��������}3�N�v�ST��c���~��\�s?����al��,�E�;P/6��0��ws�*j|���A��>����U#T�	G������e�
@6��7Cm�������T��GD��.���k�����
��(���������e,�
N��k,U�E�#��R�+![�'eUC�p���}���7��Rn�r��*2on�1�vU}�����+���Co��?'��P���st1��A���D�{6��A��,Hz��ZY0�	��a%�``
�2m:B���o�h����� �HA��0H���%b���=��")�	(�������6�I��P��R|�y88�PK��?CQi;p��:�X��%�*��	N��k���+�'�� ��y�L��F$	G����
����H����\��)����,�OX�j-��p��}LWd `�-:���<]E��}\���aoMS��Q�u{��
>k��r���;����K��y(h��������L���j�P�
N�d�
�@N}��q�Q;B�e���7��+P|7��Z��`���E�r��������Z���L�;)yZ)}^�y#=�9�hH���G�?�����]]`h~��h.3M�H��2��	�.��5t������
�aj�h��G;�&%
��@A��AY&��b��AF�]v0e�58��x�?�t-�����3.�C����_`������\0�}�?�<�j�A�iSH1M@��A���:�����nm�f4?y��c'�<�ar]���X�>��R��J�Z�!�|�H�����t2����
]7��@,�9R���>��a������?&��}~�tvb�R�}6#���@k#���y�R�v�P�\��`�n��Y�PU�u��(E	G�f[�
���(0��Z!_���|�1�Y]]�XfU�3!�yc',r�i�*a�"�A,���C�M�nd�(_d'?h��i��o"�������d9��X��r{&^OC��
�����y~�����s������"����1YuwF��k�K!Y�t8���V�!@8��$��0���U�Z��s�=��y��`�@A��a%t�I+�S���b=��i.q�B�^G����^���g�����f���i�>�!�?���}�?��IF��]�)�f�����<���6���v-��f%�G��*�lw���i�=��B��� �Y���=��x��zJ���u���~��n#�|�w������<�B�]�]��	yG�*�Nd�����v�� m��u�x���������6Ye������Uv�<�{�=�����.y�#=�F�������BK_g�T���R��G�Y������&YH���'�|�!�r�[i�I������,D:�����$W�&�w����~>��])�b���<T�Ih}2���.����Lf�BuW���AA�IL�7�b����ZoI�{�p04gz.�eD���CA#��F�u()Qn�������v����&�|��7+!���� �7�w�aH�|�����O�*HOY<�6�H���{�r�C��y��s��7�O��q+��P�<}xJ�"y���������r���� U[���|S��+����a\�6gT3�=oc�~���������]��u�Y���q=��FKA�����_8���	8������*��9�+��TZ��r�"�������i�kL����!�-�N.�( nyY;�r[2+����.|@�&��`a��Q%�\j��oz���c�}��R'�����|�IS��X�Pz�����an��*���]�����V��}(�DnT��t}��O)��,V@A��������EAZ0)�@���7�;�\��Wq���;��Z��O�_nYz���I��t�������9�r���X}$g������"�X��?�="Y�
gy3O(�@���1��L
���vp�,������2b~<%v$��s'����.%�9���_J���+8/�4�dEY���@|��t����(�~m^���j��(�w�)���)N�Pe���fCI8H)�!uQ��<C�.N��xjJ�����2f�.:����Y��
�����7�M����?3Rv�����{xz\	�y���#��i'a �ogL6�f�[��n�_�yO� e��9i�����<���!8������7h(��&�+�����G���u���>6N�u��lKt��bP����Iq�':.����IC5��}�b9�vPk
����&�V���2�A*c$�_L@�g�f�cerM���-�Y�W�U����hK=
��Qk\
�S�c�t�'��Z�8Q�4�_����6S��]��_2tqQ������"�������8(���b�O�����h�p�J�4�>O;��8C��$}|H6�<��"��gts&R����=�����=%�U��xz\)������������*�.�?g�H���x��@z�m�'W���4����vO��:H���jH��
"ek�q������$��.{Z)Nc�a���p�=���������#l����.I:v��5���K������v�S�SsJ'4&
8-�`�
��6�%��GAs+H_��mTy�e#a`���e�(�����_�p����A���O�����%S��#������ F}E��:9�p�)���6BX�+i��2>7|%�(��(��t�.>m����A�����6�@i:`"���>�.�)��|��f��O���������������"B)�Q��������������q0�#=��B���!���f���l��4�Hg#m�g��(����}��N�S�%o�%.R�=<:�����i����>�-��O�B�N��]2(@oV����E��X��n
�?��!���y����R,�d�5������!s9���<gP�c-76	0N5����p��u��WV�Q���AX�db�>K����y����&��/��/m9�$�&	���?d�%'\��Z$ ]������O��h�[@e�
���1��w�h�t�W�'*:���PuD����c&�w�l������ ���Y���|��tOI�m�AJ�I���������!�W���>�Hp��i���<�����*H�~�	|w
)}~�� =�&_���*���i���d
��$K�JHb��um��HOs90>R���2%�s�<��$B��+��u������x�����Z�.��WB����)��k�-����u���ZO<{x\g�w��JH����d���:� ��x�{�	���5+s{I�O���v,?W�e+7`�4q	�V"��_D�2�^	�8T�y.\��:�����1�0[���l��cu[�1�0*#z�]2�:�e!�����:�Vt����M'"������r4$����?�8w���1O�wb�
G��=�m�fCAg�o��+����dB���wn�XP�r��7�Q��.U�a�2JBT#t������IH�"��<8�qP�d�=�ZV��8)t���xvO"��$����~�	��R��G���:�P����hE�5�6�Is��P�<�T��
�Uy& �c��S�#��YN%8���nI��VU\���X|o�Ao�b��Q`��5tq���T `2s�?�w���:�RpZ]F�p9�������A���SY:���A�E����!�����GQ1���Y��H���	=d��C�^�=��e�/~D��tq�F~T2���%(�c���FX�� AhbT��gcJI��}�����S�GJ���[s��w��H��)1'Rt��g�9��������</�������������:H��i�w�K����D��O����I����I6oB2�vw��u��]�[�L�����a��~^P�"e���2�)���O�������nA�z�$�%���X$��h�z��V���dqOA_]����s3�����0��:Yt72�k^���kl��GG�RP�������_�;��*����H#�G�8��^��1D�af�M3��\�HX�L���O*�����	�^�#��zY�����jC�����X�q���@>�q8.6���M�qL��.�,X'���$s
�]�I�
A��Lt������4jH[�?��r���7
��;�B(���2��3U\���@�����&�8��$�G�����y"y9hx�r�j�-4��Y&����*]���y�Xg�����	Q��F�@����?G�����7`�N�����!@���(@���*�h&�p�3A�Uyhur��><�����{U��5u��[��'@xm���F�Iv�;b��??��@7
��p����=�G�c�E�<��y$x�q��h��<1G����#g����m���K���GK����� ������,��L� ���<�K_�%�;��m�"�HM�Q���o2�:����	5o�WCcv��W[���T�"!��l�<���(u9�NGDY<��V���RX"��hi�K����jn��1�F.Q����|�##" 	�$f?T�,������J�V5y>�p����rg�e���D:��5��7U^3A�x���������`����)`�)�#���l\��q�V���kW/>`M����&q	�?��jb��z�S����:J@B:el^�~��s�VR���Q���\,�HBY(,Q@�qP������*��<����u3�;�z%�7�V�D5>�_�\,���j:h	 �W�z�D��@L�r��@��k�g:v�����D��IVt����JO�C��X�4��xf#`��{5|��C��!���nx�t�$�)k�??��w���v����ZHb���<����q�>�?=�e�3���O�����"��+�����'�w��t���u���Y����O��*�N"�b�w'���:�N<�g<E&�����1.�\�q���s���s������5\E��BnN@r��j1�,�Xi��o���f&�*�|��:����g���z6�H/�S��%h8�*P��~��+�!�]3���	�&����u��s����NBe@�
|f��j��6������'�%
��AM���20��<IP�X(�lS:L�D��"�*���_a,clqR�1��I`oO�s3������o�
�|+�
���'��
;��h����E.:Q�l�F��v�	�&�PRNt\�?�</D9�L����s������q������U���D���g��E�����KBAxC�6=�Q����V������Q3���3/
�����+})�F�JJEYr��%Wx^��Y+��4f����t0{�c�NBK"E�\>g�@@�#���\�E�^����z4�����X����]#dtS�_@)C��,��QPV
e3m�HgjLTq����6Cs3�7l���+\~����Wd��^ 3����ww����Rz��j�4�|�Vvw}�r�b2#'��V����y���HhS��U���� �`C�]>:u��p���l���t�^���E��@*���8	mDE���A�w�L"�\yCM�&K��Y?wJ"#�F��c�!u)��s�kD�N`���i-+"b�r?"�m7&@�'HP�L�~�����P��g��6�P&	2������X�OI�G���4��GxD$`�2���_��d���4�TYh�JK%�"@���%N�����*OS.����t-#~1��q��[e�2���Z=q� ����:����7	2U$�q�+��pB��;L5���Q0��Fx\�+i��xe��c<7�A�(�����������S�P�x@)r<Ds�v�kkj�E�8�}W~�q�~y���^��!6BZ���P�	��,�w�0�������rekTa�U_���3�o��Qtd������0DE��Cv�Q������9
LP(�,{Q�z���j�b\��`��{��N��o���J�)X���?@���5�g��*��Uo4h0����oGA"��k���_$���@�!�`�g�X�Wq�>����g������J��x���������V62�l�&	���/e�.��,���3e 4�_#E��&Y��8�����R��4�T���UJ:�IE-���8)L~3���4�"���� E�\-�������Gx�l����������������g(�|�I�<W:`��$�v�I��D�'��B��<t��R�t`y��7�W5`��k,%�1VU�Un��fC/�M'Q���ow.Ls�4]����M�� �����Y`$���Y��+��q��_���=�JL�u�&�)E@����a��m*"@}�n��*#�����d��+�uP�=:��r�����p�f�5MFY|�H����2�"X'8HNkG�Z�LA����hhh��n7��"R=�S����Qe�2�I<���| ,E���z�.�F�I1@�Cd(�8&E�N�IF��kX�:��qQM��nN���9���~��{��+,��\M��$c��S)]�zN����X��o�L��b��a�I.{3��'f�u�|d
�m���"Gj��������>�<P��/.F5��b�S<0:�C�;�3�g��,|Gm�b>3=����oNV��u����Z��<�~h��p0��kn���N@��&��������L�����l$d'c���xEK8��C�L��u�)�aNV-����xg��Q�3���S����(^(��8�@������nH��hd!�U%/�pXx�\�������+�����p��B����q�"���?��*M����}��E��Sh�Hpa�/@A�:�Zi|�d�X��R ��FX�����$�`�	�%�\��Q�B��M�)��est��`���cy���7�@��G�Gg�4����Q��5s�t�x�tC����r,����N�c�����|]'��Vf��;�^�_��sB�
��F��.=q��R#���#8�2y����Q5�������}�����{*`��Sa�X��X���3����P�c�o�j�
R�����p[���At7�-���$�?�rW��#|�CsM��hhV��!:�H`��4�E�2���C��nTg<��MH����m��(
� �I062yC��C��M��.	g8�t)03����&p	X2B�~GQT�"Y+T��>����Q��v�b��i�X:��1S?0�.o�ht]	
��*)^MZ�D��b@�a�l����b�?�OX��_��$�t�WO�����;�l^Qi_��U�G6�[��V6���0��]{^�,��V���_��-�S
��I��x�����V9]	@��t���a6�K"��zn+�r���<bo@ w�|_�Y���(@��0k��.�'�^�!�'�)yIU�:�$������$�R�����DT����v)���TPU���	���
�����n��Jw�4�MB���0�S��.�pS6��?E�P\�.�D�K�����#�w��eo\<U���f
�4�����p�.-�z������n��E�u�W�5�SXt ��G�h����os�
���<���H
��T��(w�+}�;y��s�N�\��-`Z��-y&Q�-U���]��l�����#h��p������t#d�mj�{�K{T=��'.A���:���=���;����;hF��*��f&�G�#��5],CV�����K_9�rWNjH��1tM�J����?:i��	���U�� ��y�Q��o@��i��d#��^����������2MoQ ����uB) #�cq/�ab\�0��OC��;v85�]1�zO�j'������������Q%��}P�C!��0M��N=���(�����'���(��T�Y{��
�����_�0NP�	�"](��4�L��ms�O& W^�?$b���Qy��AH����)D��R��e��H���T��4(��*(T#�Pa>��Y��k"�^�B������"�AjMsB9���g�C�t�`
Z_�^gn�<�y�$��E�@k�v��+��4���93�\/���$Fi�:V��d�z����pgf*���s�>��2"J�9�`�����V��iB��xUs9#������a>X�����B1���y*��,�F�&�U(�*����
zF��xk�/��9��\v�o���|���e����\1����pT`l���?��p��Q�Gq�R�|wIr&`|z����l���v &8s�z,6�x[)|L����������-�r��C^/����o��W��R�]7�\Db�j0��N��0p]��i=���������dXA�V�.F�G����pK>�/daa��2�L ����Y���]��2j��mn��[����<�@<,��Tp��e�G��
��.W|��?��.s�i�������?�������f�+!e�#%�G������|gHb����t-$�����szN�����>�VB�7w+!���u���YgH��#��Gz\�9���jH���7R�;B.o��n��I�����S��q���Hq������J�I"�k!=�srJ�x���ZI��^��k��i��.�lv�<'��������j��}^��K�d�83��6���Ek�GzXg�H�ZO|�������������H��9����f�_!H�'^�/c{s��<
�Tm�Eu���t���C|����y���������|}��	(X����e�/�d��]QOz��J�������O:O���pX���=�~L��`�f�@���������}m�����:��R��Dh�g��4��u^����
n�(�"����������>�����_��c�X'��Lf_������W4�NL}g�.
"���vu��;i{y���o�;_}o���fg{��N��x��9����j2��4	�1�E�����m�i
�E�����&����T\�!7_����M�D?|�B��,	��{�Suv"���a�&��E7Y-`W(����B������(���k��:���Q��X��Xz#`������6FI�%J|���9�����/
28����/�y����\J����I��q��TZ�s�4
�t2��X��2�s������������T44��_�F� =�����~���6P�Bem[���)��9������N�	E���J�S���� *n0�m���Q��O��2��i�p���U�����=e��^+�	�?���uS��P$��iZ��?�$8"m������v4
���e��*���=�q����y�M@c/��I��s;S����Q�PJB�E�n�J�8e��=�o��1�j]�
��=B�_���8�	7��LLr�{vL��J^�����hY��'ci�g��,��hUG�F2A��]&�a��e���g�D���G{����n��9�����;���V{�Bd	�.#���������|S�%��H@�_�|V��#���"���Q;	ayHHC�	1@��'f������
FzD��
��)��hCM����!�l�4w,b�`gf��1�*�P���Yt����j3��@�Q��wQ��
���+[���[�^`~m �V�����b�9�}�V��8�.���X�hK�eG�)�N� �������0'�d���cB���p~�v�jrh%�}y�����V��q��.���4���c�1�:��v$�����p:
�(��Q��B������W��()@���#C�"���u�i����M�������3L�A������W.�LD�n�b�z��AV��C+���^�%�F�&]5Z��/��ZvQ���i
�6�{'��1�pyD�e�Or�����.�����1�.<��F��?���
��&���}���c`~������5�p+�r���1>��?�O�\�/��|j�A�����T6=��~�yC��Y�>�CF�?~�IFc�c���|O�U�7�P�J��@����E~���o>D1 �
7S����?��Q5�C�����~������4�+��@a������������4�i�_�����~P�_D���\@�������?����/E?��A����	,����V.��&����;G!����l.���Ds��G��=����clK�n���7���m((~�����1�<z�KC�?�-���$���B�\��&Ypd*<����|�@��Ks�����|?��d�?�Y����\����W�k���>q�I�:�����u����F;�@�8�}�9'_\�d������\l��#?� WL���Yh6���U�������H�d�)'9.n�|{r��[���3��(K������(�
y7�2;����R��tb�JL��~t�=��V_|�Q\�]�� n"]f����M��q7��!�=�����$���G�"c����K����wl�;(�L���gY�
�7P�Pe� �Q���@�z�~?�D�QJ
�
r�m����LP�0�(`�g��7I���D��2�q��-��O�%2���8z���&�:�������&q���77�.��2h���>�n�����l`�:j����:h�A@C��}6
}��A�\>x�v�T4c�����w�"���#�|��$�����^����n�S��,��,����8?[�M ��s@Gq�M?l�O��>���w�����c�M���.L6�w���(b8F�����\e��k/ ��-�>�"��TZ��<dIz����)�O�Ot�������,�U�q�:�����r4���P��M��[�^W|�8��D�\@?<.J>.M��Q�I�
&� ,��qM
\�iR-�,�	�M�e2��qFQYm����&�7�(��3	�����[�{�x�	�M�r&x�S�h ]z�^�g���Z��������B������}qU�U����,������(����*X@�q��H�������J�w��Z�S���`I~W��O��p�ND������gG�Q�I�#�����p�@�3($��D�;/���#��,m��M�1Y�0�D=
��Z_O��O�n������
�*aq��{�7@C�}��d>�	9�ypb6l��Q��j2oR���a f�z5����J4V�y��(�D��{���"�����t��V~���y�����3���*�U���^�'�?���������?��L
��\��;D�q���<��$1�oy�<+W�u.D��m�����6	���/?��g;��q!���������_j�&e��>�xnC�y1p	�m���U�����[�{�.CC�������ZV}���7a�b��J����D$�E�A��1W��`,�P06�N<�Q��p�-�#��o6dS�H�Age7
�1�!���g��&����T����GM.uvsA���j����|�j���Ue�|����T�%B1��T8�	���h�!-o1���%\�T��!�J�7�b)��U�jt��9��G�$�����I�.u=� `8uYIX�^��~5�Rfj��4�P��j6rA���d��t�Y�s6�M���P����*d73����J�����	��
���B=
g.�a(��X�]�Ig��C3�v��&�^I��~/_���0�����E���z�B���
�����CWP�aC�K��k�&&IM(����5Jct	���^�*Zn�EFf�5������WS�����Q���?4�&�g�9�P\
,
���f(W���r%(��CN�6W��Z�3	`(����Pdp�'�\
�|�ZcI�pA���d�H���<��QZ�o��e����HV}��
R�c%��"S
�N� ���96�F�����&!��E����`��&���	P�R]������5:��l��,&��L��/$i�p �5HU��O��w�?{o�+��\	���	I@�|7"������z$�4��� |�A2�����q3w�e�73c�`���*�y�$����c�r8���;
���R]W�������AgA�DS�@�}<u$+��MR`F+�2A�K���`�p-C
X0n�W�~�$�R��d����r��D�oc]������D�Y�I�C�Qs�>������# V�x���v,&�@��o����a�8��*��2�pMA�����y�B�s���w�E�b!�\�C�a~J�"c����O�6G]G`v[��u��t�^l*��`\@M��}����j;�^����ct��&k�c0�k��5��:�M����W���r��<�X�(�>�d&�
��cq���y�w1����#���d���bO	��l?�j�P���OAN{�=�PP�u���R�i��8�����ATi
@]�[Z�<\/��+,V�Un�#�2u��n�p�33�BS&�S:����\���=��UV �5�N"%FQK
������x�x/s�����U����C��F9?�����n�mAd�	�
�'�a����b��
j�(^��O����!%�)��8l�4����&��d���H��]��f"�������K�2���
Dq�!���<@�cTM+:����p�7�p��d�)��WA����@+7�%������ �����q��
E�KA�h|-�=;
����c�Z����c�=���e�fjj�w����,����;���[Z�i&���1�f%*�����$5Iv��0!]3���$9�R�c��BP3����J�ewJ�x8��C�F��
2M3��!��$�!�V�
g�N4k��]��B��T�����h�+e��+^jp�p���f���l��`ul�:?@���W&�t��~�m�GK��qL����b`��~������c�x�+ �P\b;P�w���L������o������O�+ �b�0��v_��������b�0�H����c4<���c�/��/P�	��1�IYe-�6tC�����������7�0��������x�6���9�c���Tl�"f��{y,��@���q�cX1F�#�����M���Ta����I!�5~e�8�����Qd�?��r�K�J��u�D��\������
�)O
X�H\S?�W�$#W��cq�)O!"=��O�����Fr�d��1�'"e/���M��m�nv
��6#�$������~W�
���6� ��Lt"��f�y{����v7{�{��JC�YhH���)�o���D��H��VA�x�s�n���g�����3�67A:<�oo3�����������
����*
)�T������*
�F������t�#m6��or���<79U6O�m���aO����0w��w������?���	���`���<~#�$I�6������M�$V�f��;���xW�!�
������XI	��� ��\$�x>GF}����(��<�!�?�]���?p#m��!m_v���IEJ7id��vO��)MEz)6����t�b���.�E�1��8�f��<�8�T����F���3�H���H*��)��3n�vO�����JG��f=�mf�ns(��fo�ELD:R~�y:�j<������r+���@������o�
�#F
�Fv ��F���IGJo�v�O�Z���m�����.��#=D�YT����F��>�%b-5���]z��FN:2�>�����������S����v��]������{|�������DD��t�XO� `2��T+������8h�+VcuE>f��N�%1�h�8���Y;B�bu�c`�e�A�?H�H1�@T���2:K�����|L�����U7Cy(�NW�e�t���C�9�
:o������W�*&��h)��J��H����3:�;<L�+Z��-�|�R4J���C�i�������������E���B�[�P�`�5JX�����1�C���Qo����B��;��%ot�CQP��#	+��O,>���R��4mvP;���V�l6���RC��U7����O�K*Ay�7����N�-F����8o�?3�w��]����x%q:H_���$U��,��(���S�*�'9�g�$����E����|��I�Q,�b�����e��w���6H������"=��n������9@C:<l�qP����e���"m���m�����|��]��p�y�g��f�!m����*PH���:���S��������6H//���� w���m�O+g� �^�n3�����VH�KwE����BI������i{��F�H���eQ"m��o2���iw��|2HO����Az��k������6���ko�	�~�$������9�����n�p���k�_�i�G��%����'��s�-���Eh(�&y���	�25���� .�hB���q��7��B����4�*I���~��rQC7&hnbA+��j5�1��b���My�uZE6���iih��#
+����Q����~o���t���@��Ep����Yk���V��hZ@G�R���j�pR'\e+��Q���xOla6:�����������` ����u�;tgy]�>���'@�
6h��}� ^�|��h$������+1�!�������8�I^��w���X�%h`��8����&%HHZ��]"E�qa)�pF����u^tp��).�L�3p�c��f�r��%�-YRY��mn�!��P��P��q�#��l���223��>t	��m������0\R�y Us��/������-^)�|�o�Y�������2
���1)��v�A�m_�N<��y�3d��F�T<<���{��3���.Ez��P1R����"��%�U�tx(V>���e���xx��AF>���;��Ez��g���iBzx�V�`��}�zz|��g ���=����=�o=�t6�czw�5���_���g�Az�<�|$��1���t�dO+o�	�!}\�[��x(����SF�2����'��w�83������!+�����vl�I�B FDB���	@1��j�DG������~���"�p�d�����.�?��O86�������H/����&"�������2��IFR��C��6����d��1w�GO����xHl��>��oq&���a�w�sL����~Q2����0���6�����ph�d���W�R4B��Bc&y�O��U���[����f]��f��_]�'�������Y/it�������e`@�Fx�#v�VHb��5I��[M�v47`���2�n)L^T��
e�I���ym�T�>���5p��R�LEU`o�O �1v��{�co���O����@�N=�NH�Nyg$�W���S���+M��D��"���,�Da�nH�6Y����)5:���JY����7����fe�����_�5�o�����f����������?��Q�����2�?����o��{p�z������7�1NE���?6�sZ��0����
�6�?�<���zj�/�����v����������gs;����4YLErJ'����3��M?����8����;B85��~�a�y�����=M
��I���������0oY_���g��"4�����8Of1�fj�D�����2�'P��������-D����q}x`=�����{���(��
h�gV}� �O8��\$��9���7���p�WZ%���oR^��g~���\��e�;���Xu=3;���uY���b��h@����o��p�p&:�N�//�E^�r>�_��/�	�����d�Z�Zu<��"H�/�}`��xT��������r�Z�1��'�5�w�g��e��uD�p<�D���Pv?u�?��p����5�T�I��i��"�nxg{���S����p�u���w���6;�Z�O�I���d�/�
g���FW@f�H��w��V���f��pj���"@��:�]S���]q�E ������[�����
��V����S�����|����H��t!r��n�`��s`,��y��#��_98(%��:-������+�����p������x=��O�yp�s�zftg�
2��NY�WH����SX5��p���g����� ��������{i-���E0`�.
5���L,��X�SX���x�8 �6|I	|����V��t-N�[�)2��Y�j�$\-I�h�C�Vf���������SK>�}|>��\R,���b
��wM�������#�'iY�@�c�=���a\z�C���'�\��*��Z��pe�\�8w����_A��t`���A6{��F�n�I����K@u�yk&^[����1�e�O��8��ev]�*����4��7�����@w�����>.4��c�$Ew���"���k�gU����;���?Hq������X@�~Q���`w��*��FM�������L���R����-!.��r�����A���w��N��E��n.8�z�/sf���V&b=�UYW�d���WA1�:�inCpV���rM��<4]QkS����m#z��}�O��([/���<f�%S�OQ�s/[5���a�i�t�y���#[���S�,`�%���1���H�����_�������a`U��=��V���c}�B-G�D�{f'����� �`�
@�Nv�7z<W����?�my�m����b������z�3��M�ymp���M@$���"�Q'u��.}��G;�2c'`����{d���L��C{"G|�3<Q�}����A�G��l�r���I *���{���)�G���L&ec���l�fw!�~�+}U�'�4O"�s��P�6���~hF��W�����k��:�~��
KU�M*[�T3�K[����Dgz~��Z-����p/�T�D.Txo]e�8(�,x7����uw�&&�L������}LZ�b�!��Xyc����>���"���^���@~3�\�������jt�qb��H7��IT:�����y�.�m��6B7
(j(�m�9s�Mj�;�ZE���=���&����9^c��c![���7g�A���=���ogG��;�--������C��
��m�����2�X�Sy���L�N����b�7������G�����.mnX��+��W!�Gu7S`Y��n���u#����g�O]�"��O�����)�m8o7���u�w���)����
��n=Z�������|<�����t������=�g��������5��&z���������B��8���0P���.�K��9z�p��M��(e�b�%��3���d�)"H�	�,SS���>�w����e��Y�T�m�N�E5'�k^%��@M��j��"s�iW}���<~,v������0�0/��8`aq���,�CM�b�d�fg%.a��09�N��D��n d0���������s�+�4-������;R���&��|qg^�"z�����$�������>>
k��Dgl��<���������I|�]S�X��;��u���M����%������]�H��'�Y��t-^Y��~]�t(nn�>�)�+Cq�5�9�W���}?����N3#�q�����Y>�%�3�����Y
��5���y"�uS�x������� H��1��m������������c/;U�:,{sf&y�3��M(�Az��g�������<`��P�����?&'���L�y  �Ce�2�
<���s��o�J�zI{�S�e
W�	�/�weM�_����w���X��v(YSK�������Vy|t�)�?�T�������*<�{������>�b�v���%-���pO��.�����a?X�@���2�>�W�����Bo	s .<;
���E&nE���s0�����'���w�=K��~d�c�7#�h�|��z&%��{K���cY4�sy0����F����4Ku*��f:��G����q��r����
�S���I�[�M��Z8!���~u���V�� W��v������b��dT�z�����`5�::�&���G0���%
����%��6YJ1�n�9V��?�B'J8=����
9�Z��Q=��H���t��K<!�:��:�t���"B����XQ����nd���a�����SjJ>�B��?�;Z���:s.T�*l.2d�~<�����{����t��!��h�Y*�?���I��r�����F����<m����|�����X� �,�)bfm�&���L�������� ���������l��l��+,�
m�0�VYs��.X�nAN@?�neq���z���*b����(Do7�/�:���^��c^T�{wk%%8����6gg�����M����-]M� � ���q.[}����m��*Ad�+���a��[�}��X�>u�y|zU����
�.d��1�:����%d���:�-��J!�g��q����X,�D�d]�U�r3S�� o��i@����3�f��^Hp���N3{v���q���P��'���I4
Ls��BIr���Qv�z����
���u���1Wk�k>��)ji����B'*0�+v���2�@?���A�a��C'3��ctE644�]����v
���e��C��_c����k���7���
�;t�G�/>F��V�c^X���]����8��o��)����>���(S�C���p(�Q�7�a?�%����v�jc�b%�0e�XH2�W��|s�	����b�]2���W�y����f������\08������|vtH��"��/x�\aq�d������9��r�/��y��:au}�;B[tO:,�hl����a������H�A���q=t���
�����%��<��]R�#�N���X��M�Y��U��in5��	��^V������=����S7\rzo��Is���V�;���;Hz��������Ng�9��J��yT�q��L����C9 W�:��@3�k4���.�O*�$vd1��gUM#[s�W84hzB �J�z�Y�x�H�j���=�������k����`_%:�+��c=������^��p;_��&Ez*\����M�%�`D�j���>m�e�%�*=�"���X
f���Ix@4�x�W
w�3[�y8H�
>��Y�
a^#��/�]���g��L�N��u��=j<f���K*;����p��	��s�=x�2�D���K����s�:w�^+���]�����]1�]->Q���A����6�Y��<�)����:@�l�Z�U��I"&�^��������������U7Ny���
^���\�%g�8���(���eWe�LC��TQ�PL\�����1N��w�)�6��X����~�&��N`��"��k9#�8�C/�{p42xB
p-b�<�`��_���C,��1=�"(��:��,3*�������f���W,�+��e�����{�ul�s[�*l�W������Zm��3�G>�2��q�;��?��Fw��k�
V�����=��1d���
;rn�MP`��b��c����cY��M �"�g1�O�U�_����]��� 8����������Z�F7`4��"���Z�r�n��:��,W�����J�Yw[�S�8"����Ek�C�����a��tK�m���-}U���M��Vy&��\�����*�p�Gy��2�p$���+l�&�f&��?�u�l;��B��4 ���9��� J��,T:KC�\��-P�����Rf\�i�S�]B�F&�Z��K��'����~$�X���8���_5�
�3���<����0ycKsF�*������`1��'����q��u��|��T�>O�4�D M��+���42��[�6��5U�w�����k�v*������R(����pn*i�j��\�?��OIj�!�ZhI�p�*?�CxH����cd��C"�����f����S�P�o����t���2���N(�n7���v���.��y�]��y4��0d����%X���w���Pi���I�X������s���WVbribP��.���l����[R�������G��Xg+�z�j[����[���=Mr9��o�Jj������zCY����p�
��%�6�EHA&}�+��1�e[*��|���
�����M��FC�>�hJ�R`����G�
zUUy'���cqy�|9 fb��9������3=t��g���e��'���E�l�U�3�k���rX�����l�[T���9���g~�9W�lZ���H��<tD!P�+/�(5u_���}j����BC��KR%��s�o(����d<=_��0=`����opgN*�}�d#�Ka�[71w������(�<{SQ�d���g0]�Ey�5o?/��S4�:���S�a�8=�}����H���R��7Sf
��7c����i��S,gm����V���gR$�hB�O��"N���f'���j��2��:2?�ST�w�_	�,����wMk�hgY� 4��L2��k�&z�~T�n�;�E��IG�l�l!��E�f�o�e�����p������������B�H�E�T'������!��f�^�`&��|���|��C=�y�t�*VP�C�.$�f��8@�gV��(�7_�b�h�B8^��'�$S')e���3�B��{��;��qOc��)k�h�LR����b*��}��=�0MKK��rY��M1	D��$-���@�X�V/[-�*�^�P�B�R�2�5����U���v�'���)�&�P-_�S�vb��Ru��b��IP�����x�~��,K+�oy��<=g�2���2�� C(�$o$J�&V&LG�S�v��\�����=�E��g������Fjd|<?.e��g����-��6)k1���Q�:��� s;}v ��i������3���9�����~�$�R� �~cn��d����l���:G���;�t8a3�7E!/����E�CZ��$j�������3����+t��ai�q�Bb�CL;ue����<�������u�����:l�rBX,��rV�$��sn����d
�t�v#�\�'K,gnYj����kR�E�_GY������I��\����:�H�=�����2��e��P������<���,����Q9���>�����*�dNZ���h�E��\-��2,�LN��:�L�$�����t����	z-"�<4]���,b�.Z���8�f����DO���xVn��|U���J�e7;����&TX��5H#����9��jG"�J
Qc��bS�]�B=�o%J�[��@�D��~��*��}�5�L�-�e�����O��5d�fE
����}x5������Wqi���`��3F��r]0��x/�J�V2����+��c����}��e�>����n��\{�-=KA9��Y8>YNF'mO��P
��~�=d��RU8�XjV0�z��
��z����� <��{��#�hs�d���>B=KjG���p�%]��S�G_s�"*:���U�X�&���:�>���zOP�y>������}�����s��M�O/,7��if>�Y�&��Wu���j�u�'�f.�)le�%;f�'������=���z�A*W��"kj<D#2���j�TJ�����>F���R��8���$xE@����X�*
���![!O�f`g�k����Gu�.G�I���>t6��H5r�x��:f������8e�-��+)�iFsinQs����l�|��4i��
����a1���"Z+R��F=�^�i��b	�H+|�5���o�=u���T������K���W(sNd�����}R���:?�(������k?����<yK�yX>f���������Af�LrvU����N�}QQ��=:k^��LY����s0I|��d���+�Gc��5���E��o��	�1��`��SxZI^��5�
�����w�Rt?�����N� .=�k��������b��C��89#r�p+Ob�PV�j�����V;PMK�R�#En�[��	�L�e��y0�9Qa;��\�B��i!�*/�4+ur�C:�,���
�q��z�s>���������O�\dyo*@�v.�(b2���c$'�aN1Q"I~��n�FY�-D�HE��%��H'�h\�����t(O^���MmT�R�=����^���6��e_��Q��"P�

,���G�8��!��������=TE'�� S�&1�8��lN��C:� �Fvf��'|H�t�G��-���xx����g��W<;V5��O�A�
���]:��u{��)k�mF��q��D2�V�(]�"�q�^�6������I}��D�/�K��q���V'�����3��J���q�)�	��4;A���S�,6��l���Nf��Z]9����G]�f��	x<�&�*����]��b�cX�������tT����ehM=nes�`e�j�6�����M�Ryr�Mz�E1tb/����%.���`��I�%`��-��V'�����"��;��3�Rc�;�ZU���y)�8�z�����R��������f�k�kv����S* ��:(2�1��������#^�'rjgZMn�O��4�]q,{����@H@_2}G���`�^*K"_�~�6�.l��v��+C<�YoFC�4����7
�b�ds�A*�l�3��zw����^*X2RN��S}Jdj�P�.����e��^?v�
�i;j3n)�M����tp(��xO*��nr`u������t�q�(��T �4��^����$a�X�7���n3l�>
�k�����
��-c���0-�[z&�(��:��^�(Qx�z�G><��m����m�%�NH���\^_{���VQ�]fq��.��|��_*���"(����Nx0K8��-�^�u�T6v����*��D��]v�:�YO��D��h����-*��f��za�iUs�4w��Q$����3��o����5������2@U|5�W33������nd�^��FC�yv�s,���3�l �`�����i�2�n��,�L|�P*��@��7�A&���:"+��5K�=�qy�t�5>��
O��S���7���K�4G�u9��T^����wp�����Z�+�3����#�N�����3�hqfy�X��u{S���,��x�.�~{K��Tq�;w#vP��?������V����0bwj�<�K�
����
�I��tK�Y��-�B9J�^m��H��S]:��#�7K����{m2rhV-W���V<<=��a�w�0v�J�:EE2�>�sbQ�@?^�������J"��p	��H��Je�
��uJNh������QX��
x l��*G7�ii�Y2�i���ls��W��+cC�r�[�����tm�[Zi��J����Vo�����Y����{�qf��p�v�Ss:!PJE��
��ZGf�6
��}9r��:	:�_��}W+X��E�.�Xv�xm�"�����wa�Z�8I��\�
�#�Gs��)�����]#+����s0	�^n�1����X/R��R����\�#I~��]m���B��#�s�zP�-�-Q���F�00R�nmN�~���'n�/v��r,I�5b�{t�dG/z�V��Zo�f_@9�g�I��LQ�6�c�_�j�D��7����g&�X�w�S�����p��<d��>�_!�,�$��R��\���0��XK�G0��l���K�>R���*
�(� ����:��H�Nz"��u@��
�b�(*�-*�<������v�/�Cd��o%���V������HFJ�B[w�\QJ�tV,Ri��:x2��MN�W����������/�j�Tj���V�6�
���>k��L��XW PZ�������������yN�x�+�7h���E8��97C?���}��b��~��	����}1�PWZ��"y7C���]�k�FeVR
~���p@D��:���g]j	�3p���@��%����p���<>'�������Z_��S���BbVf�`�(X�J��&�,
1	.%��pB�B(T\7Cy��r+��o����<R��+���oE�b�"��8�K� ��r4��,<T�?�%B���J�7�d�M�Vwi�Vte������8�!���]�0<�,�:�W��W��%`��(l��+h��)eD��N���-OC�-�2�A���Qw���Iu���S�f:�6���o���2���'#�	q,[*�2��`�~~&4��$�+dn@r�`�b����G��0������T2������Y��l��c���f��
r?'T��=�c�j��y�3�h�
����Tp���������]�$Sr�R�3��!�b��P�[�R}DKX��W�������,5�Cb��n�k���I�AoG����3���Q��Rs��:�(id�$�����B�rP5Jt����+z#�W�4;��I���b��uc�i@��t��kaw;������O��J)<�MR�:�K�z9M5�L���7�E��T�j"�����|������8��`>v;��z��p���i���_rq+N�lO�
K�CcCW�����/A��%#a���(�u����	f�{�r�Mq��#�CW�	QX�"�"�*g����[��K��.$$n����qi��x�%��9e��mi9�����?������@_u�qH<+�B�������)�W��n���vY��I��'�(
!���L����E�����T��r�p}��	8h��9��<Qe�:VH��NJy��P1tBI'�,��\�5���Z�'\�M���12�L��O����	�f�?*D�E��k�t1YP��pKe�igD��K���;�'����O�`�9���4�M��~D!�����
TW�B�m�.�+�d|�r��KHM��[�Y)F�L]���k�):���,��VG����V8��������C�v.�
���[1*n*�\$TE������Xzw_f�{	k�Qow�b�\<��`�7�=�t~	\	�i�t����+�C'�����L��i��}ux���qw��8����5����)�Y/K�8�Q<e�&�XN&6ahG�G��?�:�+G\��sw�I=���:A�Apn�$(��JKY���jp�br,����n���mp�_G����<>���y�@��$}k�����5I���v9�`��^J�g��E���v�]���>y�y���V����|
����=�����:h���N��POn��c��Ng��qirn���d>:J3�db�Ym�M�9�Cyh0��J=�;�Y��UK��C����p�bV��F�%5���kF5y��P����7�0�c���aqM��<_")������vp(�eUe
�=rF�%%#N2�R�(}�n>�U���1T[��M���rZ�+%kJ��Wt���>�'�W�4��m�!w��2T|���J��ekznfjsH��`O&�h�"���4|�%F�"�i���T�_��6��|��/���1t�M�#q[�y 
��f����,�J�%�78�������$PX�{a/`����H=h�#d��f�L�W��m��fx����5
���Xns����S�N�������M`j�B/s@j�_�21������x/:��y+
��+�������]����yQ
���Thk���,����=����G F#iz40�������o� ��T�Y�A@��J�P����!��^z�TZw��c���-���8yH0D���q�h��3|!}�G���"��0!���e�������4���#`XRd�l���O���k��'������
�\��jN���w����W.Ra���tj�TjV�^��[!�B.���j��t8�7C�����B1G�K���Q���dM�? �����dY76O�
�4b8�W����&�2��D]��<�
Y���z�]�vj
�f?�,��]�WF��Z��>��	�$�?���G'�Jl�n$����5��[,-E����jV==&���m������Vvd���L���	E�3-��]�����\�Tr8����)�Be[���?clmm.��I�u�k���P��6�!g�W���~Z[�kW}`L����.�[i1��5Ba�C;���Zw�#��P?7(K$��q.��,l.
��7�����0�;�k)��
!Dm���x�*K:�.y��D�rR����ns/9��,Zw��2c��q��u+TS�'_�����yjnN"��u��V{e�F�Nu?a�x]){V�;����NU�E)���a��!���Uy<��	R9����2J�-"�����P����/q1��������;�������?���.�:�������'B�����xw���d�8
u�$�����\w�CUC�9�+R���
,��M!!y�^��8s�������AQ.)b�6?���k�2Y^#��[���t��T��JJ1M6@8\��Y��L�8�!<��A@1�^��6�fx���u�f����6KG5'�_�O���SC4��j��P^@���%|�D=�����t�W�$M���Y��Zx��e�vD�x(�� ��m<
z��m�NV����4M[��J�Xj�P����bH����lVa8�w�D`9	*Td`����c�8�=��p�dbXm��k�
�z�I�?D`�(5��T����n�*F��	�����HH>F�dA�O����/��%Q�U�������'n����ps��H�U���@��R��#�p��U�t�9Xz���/�����c!O��������5}uD��R���v.��� � �ij���^ '���`�=!����:j%��7u��{3����,���������>�m%c�C��}�J���~8u�P����&u=��
&��g)LY��p�uB���"��������� yP�^[���X�����(�k]�wo1����'�Qo5�\��v"hF2XIw����[��p`A�'g��MIY��Z"5����r��DwqO�6�������c'���aa�����F���j(e�>v&�����y���A�f�7�)��O r��1eM�� �}P����!l���#��9V��+���n��Z�U�����5�r�x�CzX������&1�i��d����H��?�D��*������p��������D�xgO#�-���`�,u������e0L\��"�i%2�6�}��&�Id0�j"�v��TT7B�������L%~U��&(��F5�IUb_�f�ld��qS_�2����n�W����D`�i���)O;�����J��Z�D������l<4�*��k�m����_��p����m��������F�2�	��"�HW�krQ�L\��,��^���Rz*j���!�rx� ��(~b����J�����:��f��b&����4<�p���
����L�2D�5����@A���b�Cb�&2�����N]��)&���XS6�FPu��c��L�I�U���z�>�4�K��W+1�m��i��5$P�I�`C��$��1�_�XV|���f��N���j��vb�IY�A;�HR�V�������:5c�b]�xY|�x}�xZ�1"�"�a�V�0��b\�x�WW�'��U(Wq��!�O����mDP���U�����	���e���@M}���������f���Y	�`Y:'����SA`C�Fz�+e��G�Q&I����!Fz��5b�D�j/�:��Y�DD����9�I:4guA/�����mc�]�V���A,�AEKYjTe
d�7W�QZ�sm]R�&�[=I��lQa^
���aL���O����(��!����@��A�w�H7h>kv��Yg)��
�:����D�����������n~��R]��YW������8A���?m*�qe�an��4�vE��u(�j��-�0�
��o�:�K�c����Pb��l�����<�cV��z�E`D)zh �I}{)�J�d_O4bh@9.���h��7���6{/u�E^~aD:�O��@��%k�{���AY�#����lNx�(
��K����^��W���E��P��'��L����(k*��Y��7a	�Ge�����|Va���7��__L�����v�D��$��P���#�����Y�DEa�B���O[���M�����7�������(��������Cg.�l����@�C1������8N54{�P�Q�P���UR���uS'��6��G����C��!���F	"!ZL,�%���G2ALh�V3(9k�|(cY�d��^�G�U(f�D�~�.��q�wHcE�~
D���9��i��'Sngu��F���
D��$9�r7��2���f0�a�������8O�?��K?��BU��������`����!��7�\T>�+8��N!�`N�JG	���0�d�/�/�\�N�0��CzR�c'|�6*kM.vv�j�HO�Vc�:������zD�B�I0d�����G�bqL��Q��a
IFe�[C�HQ	i�������i���"`
�9ae��N.���K�jB�ju�~��&}z�=�l�s��TP��1�����"�2���|����*�f�
�����;�9r�i����{�B�)_u���brj^�:��R>�*!������!�3A�����
�rcd����Y��c�o}%A��|��9���lS�����DY�A�����E�&���3��:�AjK��P8�����a4��L���U��������R�x�VX�u: �&F�C]�����\��;+����ai^	�0.{�~<P�g��b���:�`�'\]���ka��s��ET^���[���"�@
���Z��%1���Lt\�xk�p��N.���C���hE����L3���,�5��BJ�M�28GR�������?WU���K��������N���a�M�E�d��Sh�p�9lj5f�� �l
gR ��O.x�)����?��� _*O��p���s ��u��Af�U���LL&��@W���������+_�b*1�y�B�	�,M���Q
c:����c���dZ��j��	=+$��*L�D�x��8��\kIEPG�I?�����,C���T�H������:@�����C��h��t�V�����U�i�hw�ME�j�Vj�:")'�F_9�i%S���TV+L7��L������.v<`ls`8�Hl��w����h�#�A���5E�������d�� 1
�z4�dH�~�?��UQ,)�4���4eV-���-���4�����1,G�
��+/���e�Q$iZ(����G:'����/�������P�.�H�1�6K��C�X�99N��N�I2*��(!�b0�]J�,���@>w�f0��9S��������"�	�mJ�]`j�A�T��r�D0~��+3��5l��ZAj?����u��Y�M���pw�- #���c��!��%�^�h[�����e��#�=���o���l��cf=�$�*]�����*��[���
I������)wy�4��6_�F����z���S_t�sy�F9�t4��e���A�8+�w@��~� B$u2���n_FEAE���U=����o#ukE�	����\o6����):��r�2]z���8�*�j������^�i�:���(�*}��)�E����{j�.�=�
�����o���r?�`F4N�=�/5��(����,IGl���*�
��������9�9rT���D`D�GC�V�6��������JG�&����5}�<��������(��S_R���I�X�<���=��Jp��R71���8�R�������+��T�pz7��:'���q���������#��d�����c�T�\�/�~��	r�T���u�� $�i������>=E_��+�O(�����g��9�}�nY���k�xU������y�%����a���<��<����2��8�A����0:
+��+2��R�E��
e�c�:
��O��i�T"� ������?���D��	x��7�S.�f"@P���P�'��;�D����V�0����I+�SQ����r`sVv��� 6����"&*�}��L>��)oAqX�D��P�&� �4��
@��nL��V������f�"0vl:�T��X��!������4�L�5$B�[C��������vn���������<�m�l��&������
M��@{O:/e������z�����b�B
uT6B<vDF*,�P�pw+�1)���g�+��8��D�Z��EI:���D0T-�������@g�2a�81����\�t�:Y�7Dlg%�d�V����bj������j\�J��^1L	���:eC�Y�|���+vN���Pd%�t�A?���%3Pm}i;XV�R�����(4
��B����(�-��>��F -���?[���B�IPC�����1�L��H��r��
��`*!��5����3��#B32����_c�0����]&��t��2�t��:w�����KF���Qv?�V_�U����E6o|��T���[������f�a����A2�D>�p_��r��V���JMd����M3H$eG J�PA�0�6^��-_ oZB�����y;]��������#oc:���u��b�P�I���]��:\j�'��B�T(���l��K\�_I�t�!�gR�Vm:����tB!��k�G���� ��� �X�����M/?������������NU^m��R ����������,t@�\�S���������!��	o��c���BY�X��ev&��%����q�%`E�x��q�0�F	+O����B��N�
=%������7�tX���]�S��������m�
���"�B�����63���K�����@��c�PL���c?
e}�>��f�����k����F�����F��Q���hKt����0?�e������#~u�[N}�+u<_�f�VI{\��T~hxu
h�h�����7�9n��kT�u�U_E��`;�&j����$iMb*�6�N���MQ�O��{��Q���9q�Ws�d�;D=�Q�o�
��o;�"�p[��L��%�*^�<�HX,��`X)�����z��a�W�;��� ��V~��c�j8A��������$���5"�����ys��M�\���j�p� �y���
z����@�Rgv�^������~z���'Y�^��D��Q�W������f
VM/��K����R�@���Lia�����SR����lw6�5��>�&_�*m;��R��a�$^T���-�-�3�^T�K��UFFE����q��m�����������0�98��Lz��^�0������Z�B&n���Xk�������<�@�b����^�n���5r�DXj_:HZ���
02�O�����'U$�e��Y�~+�XmA�W��� X\4_������\!��c`�������r������0R�J�^BV�Z��A���.�����LW�1���
��$���S�5��������i5�/�B3wnr�]�z�(���8@�?/����/��4B/��&"N\�2��O��t�8kH��,�
��_�Jb8����=q�LI���N�0���{�����Dd2�@��\���nbi����1;Y���������W&��]�sfy������9���g�gD��%�~�W�:[3
�\Y�pq}�������s�{�B�5��b)$]�}N?M��'�h��#�*
61
J�L�����~��
8mR��x��[��PU��}�e37&@�b�2NsV���u��	�2�6r6q�\����������he@EF�������+P=$����d_)���!r=��E/e����,S� ����������c���G ����j��c%w[��HF�����0�t�����lCR�"�l�C�1�c��U���Q�r���?��%y�*�}W�EW��:��
k�0�7��1�WV�����d��i�L�����t��P����,�d+���>
+���||�klW+l���������;�Nu�}
�H��^���tas�������+��F��3�� �����$���`���l�{,��k8��;_�<�Na�g/�_�!
��E����%��P���eL.�����_��KP�w��T�n�2�y�@���+���;�u�^�H�=�e0��V��6M��I����*�B���mQh�������2���	���MM}�zk4������R�����s;|���_���>=�^
�Z?������G�H,��pEy�P�=���2�)Q
��"���J�X�o YZ��h{�)!��Sx%5)����IWv��<�k�� ���	��2v�F���t��
m)zD�
��H=<
����Zl�������U
$ �a���Z�	�Br�tI���T���Z��H5��+G�
 �/d����������\w �(B��25��>�-����������^<�0�]<�FQ�$�?�MNl,��u���_ z�G)���b����ts����b�>�3�)�:��94�;�^ *0�1�E����>(Nb4���uD88�C��{�Vj�J�P�B7<)��s�q���Z*����>��f@+P1 �)��Qf��Rv�:���}N�0jgF���J��RQ�	�J4�� ���Sf|#�?L��t����O25�DsP�E'y���y�T��"�p<F��	�<$��J�@!�1���>
��1@(2>@d��v�zU@}`Z�Z`:�af��
SQ.�O��at�!0�J:����� M��rt�d���A��&db�Eg�L��#e�A���/)U{��p����o����
�����ZT�U�)g�0Y���HQR
X�����B!H�E�Lz�K����	���D�z<���)u��X�������S���t�8�C'vo�����NAM+�D���.xZ���!��P���������	#SM��^ �3��M�Z���2����)(�n�(V2���-K�7�u�Q"eXT�X�C��	
%d��ku���j##}���rk3���T
�:�b��y��u'Sq<QB�����.{�0���i3b:z�q��Y��$��r�>��������i���V��J o]�}����N�6TF��
�_6T��H����%�����nq����o*)�G���$���abT	������L���%�@�Y< ���H�_�������7�P�A��NNPa�$"y�BC��A�
u-A��3K+��Ct>�e�T���PA�Y'*���K+�4�i^�����Z�Xe�T�H��
����%���P������RL@����FS��b�D�t�+�l2�[��0�B�����b�#	T���b>!��5H<����>D����(c��CP��9���MP���i�1/��S�|H?^�XxHk.>i��VN�����U���D��Q���"0/�vSf������n���!$I:���
S]�[�h2B�d"B:�L���d���0:;d|���n���C���AH� 1D�g��@'����X}��x��� fA��j2HP���2B�P�\�c�m LU4�����Fj���U�T5e�}���2W*H�V'��i���a�$�S��$Q���d#����?���`@t�%�F���PMt����!�;�j�9���U%��T}��"�X���4��mY\
����Ayk��Pn"T�	#�|&�G��<�������,u()F��G�U�c#��r���G��b��w3����������S���p�[�
(����x��44�����Y� "D�N"J�8���>�1��-P�g�x?�hV����P1"�=*L��P�one*D�Ka)}C�Qaf�h+�B�����F� (���>{�����=��MMk���u��~�!�Nj*��UB���0H%z��h��H�x��L�Dr0�E��A�h@��-��D����L{YG��"A>����5�� 6��z����/�i"�����"j@��t�\�����a$:�E��m)�
:F& h��C��.Sb�DD��Hv��B�0��������,W�����$���H9�S
f���a"����Pa%�j7ti�,�n���;�:b!���{ 
����$����c��K�s��<�EPA��������Gn���Pau�
�6�$�)���QH�A�k���u>�:$�������wN��(�d�F&�.Np(]q �/8��
�'
Xd�f1�����N��g�w�F"7/^�@@�D���f����:R����SV�x<S\�L��v��b&����O�\�T��^N�P(y*!@�
^cT�H2�
���01lV��Cv�Ph��AN*��Y@�	$��=E����@8%���DW/���(0����+0j�[5�-2
I��������nkd��hu��8��l��S������'�e��OT_���zN��#��Di���X{���*�5V�$d$j�
�I��}�{!�gm��^w�X�ge�a�/�[���RQ�J]��9g��X�5���$����cD��\�T�#d-�����a�����k�$��9���Y��s�#p`!�#|����}ZAablBz��D���j$�;�SQ�x�����v������D �E��t�qMFh�I�G��s

����OFpi�QX��i��O�����V�������i�%��PA���r5(�.���,�(�������S�&������GfP�H��2������
I��.���W	F�=V&���S2_N�n%���*��.��"3���)��i����yx�;4���(��������O"��n
��Xgja�~��
���#;�6���P��~������[�a]��r�|��"�`���wW�V�����_M����"��I_�tx8�j�����g��{�5�.�%)j]Ly��Yj���b}Y�H�V�t,���'���
c�lN)Z�>�yW,�Q!Qo����R�.��T�`�M*����t�\���T�}�P�O*��e�I<�Z�.{���� ��o ���<FF;��F�������uQh�Qy��0�Zz�XJtw]�����e�&W�Ag��X��Q!��f)j���X%��I�X=��-(GZ*"r�^�/
Q9�-E���=��*��dPv�Y���}'9(�w���+��R'b�����(,��A;�q`4���(�M�w�����&0��60�y��i�����|��8r)��G�3�6h*Z:��:������T�x�2�4�P��%�������sn���{���u�<�����.��>�����{Z����I��4��������.�D�=�?cVXov!�2I�I�W�W�Bc��3.����sh98]���]��<r�B�1't�Pq�4%:����,O}"�U�,Q��3EC��cM��Rmc�G5�H��6��UKS�75]h�B���O�Z�xn.�ML^~�����Qe@�b�3_HE)����5�Q���3T�r���bB":�|$e������4��T�M����QZ}i�y��LYGY� ��� <�h��b_�����B*�i>��D�8��Zogg�a*N]y���%�>��A��,�A=�la�#�Zp[�����}�9��I��O�6������lPha'��@MUf�6�O0��i%c���Z����1��8��q��
�����2��.�us*����}������1�>B4dI����I���R+���vec�&�d"�������V��u��J9��2�E���m:�vM ��������t5���%��@�=��R;_�t�t/=e�]S��Nt����������0��G	��
�p<�T�piM/1���LN
�*�Uq(��S�J2�)c ���;��@����V��Rw����H:N-4���N�
x���rk#��U,�?��O���Y��_�2��H=6P�
I��wL�����H���S���V\���e+tN;������t�8�]���@y+�_7?�"���8k���*_�0��t���f{��tnR"Nah���['4&!b��+X+L�����5�Z9$]P��@�"l�W�c|9��Wy�#0�=���Z�e_�=I�~g`��= Q
#��ug���.��B�:<���� �N�_�Q��a��ol�l�BH9��a{���g]��f�u��*�����mi�/�x�����Zd6V���M6I�����gx���r�(�`��/��e��vP@]��|[1�Y;��@���J��y�c�L�^��'�I�*?�������-EI;&���_iY���R'XX���D�~'F�W\ZV ~�7Zk24X�e�;��!��T����E/�h�B:T�����j��	�����R!��W2p^���]H�X�]
B� a"}"5z�|A��
^��e��F�x� �H���a1�3�8����T8h2��GAV7>����d��@�>����.�[-kg�-(kFE	S,Z�`�:a����`�uh����H���u��k����e$��W*M+*y��8�L eY�A�0\7����*�d�=i2��5�.=$�D�Wd����%�����|I*%"����]�T1Rvd���dj�@��E e���A+�����E_v�r�2@����@S!��@�el*�y)zB�!F�b0	8*o<�O"�N>���b�5���T����(H�OA�CL�{�;�.q����##`��x�R�
�Z"]�&>��0_l0�H��0���8g	�G��I��q��T���=>"���	`�bw+ 1���,�6d< �\`��M�����ac���;�y�
��:���t/�����j�?����:��4���#����ct4_�*�[��::od��]6X�=�3�l���dux������7��l�D�t:����|%�	:�,�`SD*I�����~���h�rV5m����T��\����
�q\���W`�Q�$���^�J�0	_�$��*`v�:��{��a^u������F*e��AG����F�6c�\<�IN
�Ma�\G)����P�9c3;v<g�hpdM�tB�CGM�����v��������K��8p6N�'�pV���,���@�m��������V`��D���wf��S����V�Wf�W���f�>0Ql`�+�����W�W�@���!�����hY�z�2���:'.�P��da�S�t�^��2��s�d�r�#P���uM��V3s�puO��OW����V}
y|Xj�s���|~^��R�BL+
H��0�.�c1��.q�u��ZSTHm?��N���S�`ek���([1e��2�z�%!��t�2s���T���(��jF��Q���7bLR�l���6M5���RT�V-�~����nN�����1h����,��t-,�%�1*~2�N}'G%y��'�h�2	���?i�E���2�J�����%\�=V��0C�+�}��BPI?-Y<@�K��;0XtH��'(������3��J���"g���e�
���E���:C#��]�S\d��n���P���w�-����U=r0��21��H]v����N��Z/�1�s��2%�=�����p`���,�P�$�;�� 7�t�$Dw�64���������/hPD���:)\�(F�[m�������|����1e�d��A�W	����e}�M�[je��H&��9[��Fqgb�)�L0�#e&��By���0Xc���&v
�(c��90�>��\�|��J�M�Ms��=P4�

[L���_���`���rJl�����7�����C�Z($�2{�M
l�a����������2���#�i��d�D�H:U
��N�\7K��q��K�;�� O�-�����2d����a�ZH�<�������@�fxd�"��
�������J�`�P���,��a���D�����s*l�����)�-�<f.�/�C��<�E���:R�A9�SQ�b8�"�����W{�ieA�2.T�ZH�I�S�+l+�<�-�L�*�����c�����(,Be��2�H*'�
����2@^�sEW�cV\<�#�x�j��og��:��<��<""�>���_t�f�V@9Lb����}
d���'4C���o@�C���P����+~�
@��u�]���x��t�m&7&o�=���y{2���,!��pXv��r�yd%Q��
*����W��>��@^���Q�XZ��%B�:��
��w� t����)�",*J��f��&�����c��R>�D���8�4
�>��N��:LZ7��Oe+�8�V�7u�2�@�r����9>w�P~��:�tu����}�uI���n^��-T#�p�->H���{��Mmk�����`�VR!��i��z2�0y���U*���?��{�����[��!Cc�|�wS�"��q7�E���C9}[�L���~z�@��\���\�*�g���)�v@��v��|�W�����|����X�@����a`:�"�����
!��f`�@js�ig�e��%1�t���]J�Z�Te��-Y�j���
�OMUh��
��������2c�?&������D����
��k&&O/��r��r��jC���k��@��M��4�Z�}�b��?���w����_���@��n0�c��tV2���k����	z�bNSH��E����`���F���b�J�y����<����]�O�L��5x}O�S�
�;���aA`*LnR�����3D�\
 "�U#���I��e������������Z��V`�
�W�� �X�T��q��Ib�S�x]}���7�?X�i���x�:�k��GR�~�����$F� �8�����U������$*H:S�4�������
 t�!L���QU�1��l�)L�6"�e���Es�-Z(a)GE�[y8�j���u��L��f��x����s����������p��0��|d4X���UMH���X�R���`���'e��#"�c��+��!]b8��CGN���z;�f��������sAx�b���|=�� ��	*@�}��A��������f%�Z���d��(
I@��Y0P�LP�p���5�2�(��������@�Bp��%��E���=5�_��8T��(���e}3u|��!e�� $�]�n�]��s��n�D��E���vk�QG�W>er9�N�Q�`����yF��>n8�,y�d?��
�[��N�5up���b�j��y��@���>S�5�k��'���p�.(!r���o���/�+E�
��:D���4?KDW�
3�Q�n��?��H��+u�_��/T����
�T����s�������t�l�(A�9�R���tZ�
���#����Q>`E=6J�NI������#�.�M��TCy��m�l:)X P���c�_,�u���E�W$
v�`�`^@9�>8v�Y��"3�C"��rX:V��
�:�yy;h�T�pex��oc/��=B�t��Cw6$`e���@
����t��(��*F�eh4Y��d�H���3�N���g���P2��Q�58
K�F>��\bC���u�.����%#\�,G��Quq�L@P�����xr�1�@��#;�w4�+]�����[�:s��-[Mo���g��}S�hu��"����I#��y���F�O����$
�h;{NmJ���^u��
��8F�#/�eiA���\2LsN^�2�Oz�����d��;�8�]���F���aUhy������faKK�n�`BV���I���H���D@�.T�3u$J��W*�G��$���QW����b�����P��� ><����!��n��z��������0H���q�y$�MQ�h����X0�)wt���� �I9P������EXhZ�x��G�;&�j;.O[�n�3�+�9Gb�����[*�d�q����B	��MUK�T���
2��	Rw,��8�L�8fC�s��<L�h�
����|TFq�%�2�s�!ld����L�Z�B"�������*�F�G-���������(h��L+H��@�SKCx��CW�/t�>�P@%�X5{�s�����Y=��}���������T��96F��i�n�p�trpB$@]*��
�P
�ei<�!N-��\����}�3���(�����j��0�~��wze���J��O���|.2���&#�� do�E��^h'��Iz�>iwP���h}�'B�)Cw�<����2���&?@P?�z������o���rV�2L��4�V��As����\��T�QJd������'���S�V���w8W���Y.:����H��h�Q��zcT�)��"��TT��B�T�KX�������D�
P����E��������t�GM*:nR%A7�x-���2.�&SUi�\�A���v��������o��* ��!��^Z
�x]�������]���P���{��E����p{�!��2�'rA�omR��x��npp�L�� �F�0_�����]W|_$Jg}�,�9���������DkE�PA�i2�]���J�TH�u�n�\�aE~�42��`u$�o�.+�,P�AD��cY��J?��5��E�3�A��|������\�]��<,�`�<�6=������/�vJ�u�U���#�.;D����F�j+[-}+�[��JDO�� D��a�3��w/P���>����/"
���B}Qj����*�0H����N���&�U���;.�'��Cu���f ��]����HN�12N��N�Q�*���:k@���B���d44��5���Q!�h���]�1���Q�\T"�u=�E}ZK��:^��w�l*u����O,m����8��F���a���G��D����*�����q���5I�b��St0�^c�WrB�����nx��%�?C3�7Xg�����������9�449���7y,�W���
����N�����T�9h������P
-~�@�2��Yy�$�3]��P��T<����}��H(��:�/-�������`5[�����D!�[�� 7��1���)����mr:����}�u��|��DE�C����(�MV��lf�S�
��1�_�Po8��wJ=����1�����W8���sl<$��Q�~��&��~��C��{���\���j{�m���/O�sO
�J��J��4��YE����J�*���-��-��u�n�!����.�P�i�y����m��
U1��Gd�5X�-%eeH�m^*�o'S��m����O���Hf��&����%�{�z�mc� �jq���0_J�=vBO�Ny��g!��R���+
}_y5��1p�,�����#�������_R���|{��o��2�����H���V��?����������5��^
�{~yz������75ed�����I�Y��/H���o���El����o�o�_
������;�8����z2�|�~��_
�U�������
d�}�e���W	��(��*J�7
K�q���~���x�r�}�b��&��<����;��;����k<����k�l�o|��_��87�h<&�r���.��!EWt�����s�[�DL���S�����5}��S������������@c���Y�|j�z���W�W�����\L�z�c+z�s��k������s���}Z�uV��O���q�j���F4>?eU	������}����u,o7/���/}��� ~�;�������5^���^��1������!�,J�ok�+��]3�B*ys��2����]�����	y�xu����^��TT�R�+���@y�G�D��w��l_�r���=���������������H|����~T�/e���T���"k�\��m�����/������]���z���n�8�
����!�>|k��������o��O����w[���m�vw�������a�~�=l��m��w�����/�5B�[=J���y��������_�.����_�����h����p*p�|���7[��
����[�D�o���/����u��/M]}~3�U\���������M�_��;�����{���Y�M?t���iJ�a5|�xw�(�m�+&����}���&���vQ�a��*~��~�1�#������r������zQ6����e��byP�v,��������U(���n#����
%l��Q�~kEY\��+�B���K����cA�W�j���PB��8��<����/��������i��:�	<��?����<�)�p��)B��}K�p_�:D"��OErJ���/;�i>����_6���=�����Z�'����!���)�{B��_�$���'����Yg{/�7��k-{��;>�#���!��I�_�����7��~��w�f/� r��o�X�\��s�����gp���0`#X$�����9����y���q�Mj�����l�y�y��Hq�D�����,<j�G�f/����Fp69�?���Q�P}w�<�Y��C�B�����ho���*�3q�u��+�����������������,j�����0��Q����C��o�EgC��.v�������������d=�����!�n�c�sB�W�K�9�R�����C�}���>�s��P��
u�����P��J�������RSGPj�$�E�������t-z�4T(x�����36 =.0p�� ���������"���'�'�vy|��v���o�k����T�)����l�:_�h�����������d��&
��C������so
��*��w^�%sHn����i_��� �sF�@�K�_WB��&��l�?V�S���W��{��/������``V�+�����T��78,�~���]i~
V����Vo���9CC4X�C���e}���-��6ElW�Y���:�}93?�Z�S	�����8l�����E��Gk��X�[
�>�E�h�s��ZzU�"����oe����.�C���������$gW��-c��'Sh�W�u\�<`'h���c1������nKn����p��A�$6)�m�l����=�+1U��1���O32Q���2##�W�X�Kd��r�������?�l�������K�������vlF%��������~��>�{��s�h�8�zA�=��a=��Ax�=�@;�-#��>� ���]��K�F���3�c���I��r*'N�[(\?.�O�3�>{<�-(	�DN����^�_��I�/h�<9^�!�<���J�U��i�i�i������yQ}��4&��!�?���U���T��FK����A���=��M��c�A���j�C���ue�=��cS��Y�>�;�./-R�<�f|�\m^CP����&O����"=��y��^���G�i~3^��8�_�8�O���x2�����x<�������������=����Y}nH[���).������c�oI�<��V��OG�����|�m?�����
6��.J������zLGw`Na��bT�V2fx�U\����~�dJ|���z4���Q����YN�e>_Z8�&�G���Y%]��&8�Xs%�O�b���x����5�Z�������1�1��i+Z�w��V����edL~\�O/W��������=~�K���f�U���^������v&C�m8�B����/G
D�~�w������#���uP�6��X[Sk&���\#��>�
���\�W��V}�D���]���*��|?yB'����*����^?��3um%���������4�"�
J<�
�4}�����tm\�5�� ��	Cr�TD<��O�����������?m;��i�]=��x��7�u��/$l��kB5�`,����U����l��d�	�J��"^*>%X�[�k�N�)!o�y�L�$������X���'P
`o�J�0����9���x�����~�r���i�cO������!iW�*�[���.������� F2ru������D/k_��kw�0��!	L�LG'�5LY�_��!`Hy"5�0���3iQ���~�"j��r�O
���6�#8<����p�k083������%�z�O_�5��d����9^��8eqmbK;do����q���-``�0����m�_E��"��r���>?�
��:���r���}t.�Ev�?\jtsR'rP��R�fkGk�:����c�j��������*�=X��-$����%���s}&K��������q����9������[
�{����b����������%��V����e���^�fZ�=�.�;�}��Q���hK�XFZ�0x��}@���z*=N[&/]w���OR����� �_�[Z_����w}��a<L�f�M��kt��m�o6��v��z�q�"O���'U8V.���}��T���>5p|�O����cK���t��[����b����I�#�'"z��t�B���7�x,�!kQ_�ZW�����\�I{��*���,�}�L3�}�A6>��`D��1nXKD�����.�Z������z��M"��D��������[���n-��S��C���
WX����/}-wUE�N
UJ$�������v:b����g�^_���rj����������%8?��0��f��Wm	[t�i�i�r���Y7��`�Xm��[
RW�@�d����$
~/���A�^��<V��&�T��-��T�i�����ln�C^���&	sN*���	������y��,��c�<�wr��)����g�!9W�g���m�Q1
s��	
�o?;O�ge^�&���85�E�y`�=��0^�Kn7�����u�� 4��e��(=�0O1���y�JZ�����T�`r��O����5�8l\��}����Z�&E#�m�����&�S>��!���BI�=�|5��= ��	���3d���p��GZ&#5��ia]{�11�k�G5L�u2lR�\��t����#M���HX=�7x���bH�A=��%y8��OS�p1=^�G���\���4��������������C������~!�>�a���6Y��)VE'PPcy&�m73�f�*�xQ6�G��YE@"s��r��I���n
6<�� 4:�n�q&�sX������'�pHQ>��>:��(c��@�0�f~��G�#X��c�C����RN����59 ������4*�����"&�)Xm�>�=n��V�6=�"�gR�<zN����������K�U��\���E�AX����U#k]���Jy���]/���p��
�MQ��y����b�C�E��//������H�P������b5��<�J��Y�<���Y���1�D����_AU��8�I�lzMU�)�S��/�����I�h����:g-�����vD
����_��A��

Z����������KF��f��=��U]�T��oH[��������2����y������mt�����I�w��.�Ky��������[��w�}���l%�a��M1?;��(���L���?��n��o�c)�@���c}�Gq2%��s]��G �gQo�)-B�����*$����:�U}�hv�.�d||\	�\/�2W��<)L�	}��j�F������P:��u����)9�!���{��N�
��ei���3�32����������7�O��\O�qIM�Bx��zl���ij���\����������7���@��i����6Wn�����r�7�T(�����uO�zk���|RJ���^�K�B-%��A���^'�A�Vo�ItT�c���?+-��P�W{�;Y1��'�}x-i��y�Z�$�=^ �#1������V�[��}u�N��I�(����s�O����}j��9��\�i�+*����=�P�a�t��N��5��P�"���,����%���O@u�`��G�g��]q��F�v��qI ���Lj��y��GVy�O��j���L�6�3]����.�%�������
���&���9��Zn��,���u�)e�iJy��aA�L���#^���+����QX]�MX����z�)���:w�z�[Y�t�]������3GJ�\����S
9{hT%�c���6Z��,�!��'V��%E_�9�E�M�L>V�{p�h������SR)^v�Zl�� �a��J���IjZ�X9}�$��#^�y��E
���Q,��;|S"S9�]R��}�+�0^���ALZ$�:w�����@l{���W
��d��>i�� �o��"�
<���%�����5Y�ef ���%��W�$Zo����M��������LT��r<j�gA��0��]*I
/O�D)=�X��G
m�l����u2�|{������999�������:t���j�6g��j�L�
��7��fN���]�-��gQ�����z\����4D���^�r��i O��-���u��^�X���+
�����\bqV����8����oK�����ts�
[B�t{ ��I�	�PGT�N/���.��E::��1�(��������S���?{B~U�NKOu�d��tN�j�:�p��-����K�p'/�t�[Nzl��R�e	���w��A~7���z(6�-_-~ZBnj=�VU���ENe�F����18��=ah]s�@�.S2>�r�*�i�{%�GdJ!_h��m�C��m~����;s������l��%__<^��,>9�#=���b���Z�<�l9n��/��5�&u��B����vs`�����>P3#gH Dq~-���9�-	H;������b2f�U�{��e�i0>�c���Y��x!5�L���*��YR�}��<&�wy3_��"��V��'�U�i^��a7T����y8�����i"����Q�%.�\x����@�������)0�����&��3`o���d��r�N<��Z��c�"����4�����d�Ov)��?�!G�:�
����pN���t*E�R����*5`y����9C��7��y��O��f��T�O�W�z��J������C��z.H�yz\`8��3�s���>���7G�<�_�#�����"yw�7��N��O���0��M���w�~+3R(��Q�E{%���T��6��e�p��%F�=j<���D�d�P��S�:F".H|���8�fUy�s	�G��N�G��hF��{���5�Mmx@�D�h*�e��A<"���ut
�H.]�n�#D��pOYk��x��\3��P���������y��W��l�)�&��*��:H@�M�h���3?�!��$=d����s!���y�*�p��^i�lcx��xqD�}=���;/y��u���zU�o*0C�us��qU�oL*��[��PH���m����>Kb�V��k�����^�Y����
i�e���6"����?�c`<b\B�����/?+�}L��R�,�:(h2
C&}^���C^Z��>�w�#F���}<�4K� JY��.�{s����7lvL�FZ%/�� �<��-kA�e�k8��!T�V��CU;M"i)��yWT�E_��E�cwIj����{J?C��K�m�S����{K�`H��;�Z���g���7��0�R�q��[�BcL�����rONy��F9�����-�fv}�-���,r��E�`^�+|U��4�H���"6�����J�r�"fdw�njA�c�\+A�-��u�����<w^� ��.Jel�i��*w�r����	4����S�{��]A�hG�j�:���X252=i6,��I�I�dO��	d�jyl�(��c��P�*,�6�����0�;s���-;��C!]$����h�I4�����zvV
��>P���i��a�����U:c!/-ZK���<�>�����Z���@��qv��n����,�'�+��oi�eHm9\x~"l������>����
IAG�2r;��j��p�����0���]��|"�6�]�P��
XG���Bd�}u>�����D��S����y�����~�kZ�Y����>TNa^D����>�������K���o�Fot (OR���=�P�e�B�\*�.�3T���Di@����V�H3���L�����4A����+vZ��G@�K�����r{cu�{D*�:�Un��"���$]��)��^Fj"��Q>�4�=�c� ����1�2��V�&�� 	�NN������{BE�%&AR��T�nu���*/��ab�$Z3�p�s�f�A���`��u;~��LS(�z��n�r2c����t�]q��������W�?x���:������IEt�8=�]^$iZ��S��A�4�X��s}�����:*}��:��z��#�[^�������u���*�E7v�{����2l��4�3�Y��q��o���0�����G��qM��u��.�r!MF�������Z����>��G����e�v�#��'U�]��
c�H/��8�N�(�g���X'�N�[�kD1�02J��
��JE5H.D ���k3���Z_��KJ~�b�\�P�����>*d�5�Zja�-~x����U���$�0�f%��E�Lluy��9�5X�5lq��E�B�0�c���(�����*�8�rp��
��?Ac�������%a_��t�F,M��o��$���o�����#h(�n��7OD�S��"u��C�-�)E>�4��|�[�}�*�S���L)�b�����
{;O��O����� �����iu�1Q����:TP"���i�S|������o��*C-�T��)|n�����-���X��AM)]A�.�anh�#!�a��W���q��A/�*X�M�En��J
Z��T����{��H���D�� DYC|j��	yW�X�)N'�Q����yQ����6�h��[�b0.�4��IX}]���q���m��<�|4���m�uW�BL��0���>��#�eNnz]���+d>��_=:��To���eE�`���<+�U�'o�<4�6��<����A(4h�<�JJ�J�<p��A�yl��R#z�O�]��b��&p�v�
�;J��������&�������s���{�H]��"Gn���Z��

oz�9>vX�en)A���������D�n�NO�&�B�=/h�����G�IlgE����	�Ju�S���\�(�U]��1r��\���>�r�~�O�r���mez��6j2k��TcN�
]ef}��*u�Pf�~�\���+H�J��TH�����3p!�����h;�4����Us�������~G�d�2/I��YI!,kr���g	��V�59���P%�����X������B��
2��rP�`�z���K�2O4��H������=��`Hn����`��7)d��d)R����+��������0��y����~�H�����O�?�����g��|���B�g����:�l����*2Not`M��j�/m��@����y_�a`o�N���e_�����,�jvn*���IEt��tSIF�*
����a2�K����3�'��V�<o��Y&�K8���.����E��c���hM"�� "����9����}(W�������8<��oI��* V�Vn��NJ��#t�=c�Q��Sqn�W�(�����J
8BI|!�����Y�����$��4�ar�j�9@� ������c����cdSR��9����l����Cq�T�=�Z�_F����=`P�8u*,W������a<�1b�?�D��������]M�8x�:�b��l�U\A�X'�`G���S�R���������<�.9�$}��|V/N]q.�
Sh~�0W�Fu��67�w��$�*�x��A��7qM=��1z���'�e�������R�-�DU��El�r��"
cj�H���yU]��fI�Fk"�C���������a;�}�<pxA.M~���9K��Eo-�����6�\��1"�6��8k�Q���S����@�\�����QW�c�O^���[V���
R4Y�o(/Sh )����j�&�mo$��T�3H�B��/� �{�]���p��
���19N��Y�����uv7��E��E`�����?8q�L��%�P�c���C^����5!��i	s�A<6��#&���O�T����U��F$�q�P$
E��T�{
#���J��]N�UQ
m�^�:cs���f��%����3��J�@h�]�Q�,��fT<BO��j��	�<��;-��?������,��,vdW��s=,�7)��/���f�E��]#���;�Y���m�����M��u�s���g
��*+����)v��[9:�L�aJ����6SY,b^D�2�s����SHs���}����Y��|��k���D� ��hs%Zc��m������/��Ui��CP<������#�/+y~�e`���v&��&��
�/����hqb�b�])8��	�m�,���`��	]���Z��qz���le�r�X��&P]0,�@
)\����O`�]�
��u��0���O��1h���@��R��
��Z���qH����~*�hU�q�4�u�<.\$lj_��3&a&�K�����E��d��@]=��3U�>�|����9���wU����*�J�^��L������Iaw����{��Y�f��1�����I`�����NA�2�zR��Ib~��� &I��m����U.��pH#�8�B��I
A�A���n�v@�B��N.j���e��?���w��
���*��B3��h���
G#��,�*��0RHS	W���lRb���}�T�-�f���b)���sl'8UHbn��4q1KQ�l�c����_��G*���y9��\T%�H-��KJ�N<�=�*�����8�e�L�6	I;�&7����{��>���n�8/�q���AdKa�h/x�[}�����V�ke|� �F������=T����<��!����~��q��a������--P��
��$�!��{�\�6��l�I�%�
�@I/`��gUq2�yP�)�����3q+m9
TCc���������M��'��,78���=ig��R7���J�A����8�]�i���>�o�d�0�]���8��jd2L��
��kShL2f7)Ug���inr,��j$�
wj��5c�H�3_�j)�������
9�Est���V�3U�(-oR���-�BL������r��uKbB�����������
�k5�w�9y@�R������l�/?��+C	S��1��@E��Y}��R� :�P�	����|����>Y���jW���5�������S�H[n��
�%�_�N?��I�d�$N�����t�5�]��p=���$����0d���db�`S\�#=�~�.	�F���>g�'`����_�G6�`�~��JA�n��T�^��@^�
6K&M�X��.��(�C�f�k�����-fZ&�����?��g-��m�������4�l���i����������a�$�T��'�?;����T������#��1�)����uM]����N�{V3�uY�Q���<�ejh����O��t��C�����z#H���V��*�w�9�H�[SN.�8����WE}��Ra�[;:*�OB�miu�,��>k���_�`��%�dT�<���F��D{�,�L��z���h�n~�����6���������#i���M�.�EiMdJ��LSC*_���cT|�����4Z�d�-7��sm�^����=>�:U5::�K{K�K�OSQ�c��^U��7\ti��9��]�1�g���Q@.��O|�}nC�)HPx���@{���#c)�GgN0f�U|��Q��O%����QUd<�AYJ�������'q��S����dZ<N��������C�5��nu���>e�)���$]�&��x�>�{
y"l��D�v���D��&����TH�Q�}a���������~�:!)[*b}�]t��(`F�=kI�*�����4�CH�Lr^���Qt,$fi���l��"
/�i�K���f����)�u��<��KI����@V6"��5P����x'�UT3LQ	^EN*�cwF�$>\t+W��%V/����9)Y��B�����[�����1�~��H��(���w����kP��YU_,$��E-:��n���5��yZe��q���Fj*p��D���i_mwz��1��N�r����*�*��n�?�{I�p��Y88��i��]�dXe�C�Io}Pd�|����%�h�����i������t������f�8�F���4����n�k����nV�����q�*��&�O��:���i]�m�s�@�c�3�	����*��^i����)��������Id\���t��K[�MNj���z�����N��V������}���n�Z]hd�(dx���J���z,���c�c�|`��w^S�G�?|�Xt�8��
u���"���
���bc��9�0NW����O��:eZ�.�=T6�`iU��G�].�����R`��3UKU��9����q���{�#����u<'t�Q9��<:&��Q�e� Cm���P��<2m��1t�:�UH�&����!/�4$t&X�B$�M�w,
EG2�U�#�+���n�oA#�U��"�[
0�^���_�����R�~Ni��\��z*�\�>���\���~^5�S���k�V;)�`r���A�u���t)�[�?�����f�+AW�B���6fxtP2��'0�m��8I[�(U�%�P������#g���&����@_���������,�.�������k���\ho�4l<d������O!�>VZj�#���w�<	D� HC=Aa}b>�`�4��"^3�#M� ���m�i���<m`UJ�l�h8�_}����	R�g����8�v�j��.���!�}���d���[�#Yo���0��N.���$�Ez����|4�J($<W3��-7~H��)��!�����Y4
�r�CT����D�G��Ot.����TWU=�k����a����V:��4�_���/S�����I�~�����BC��������U.�=���%C�S;�)��)���������V,�gN�wc�)��������D��F����������}����BDY9���`�,�rS����b�Jxa������yO�3�l��P��Z,r���y"�
�V���v��U��h�KF�e��l#HcQ���cL���d����G
�}Ff��@���>��bS�*������8I
��mQ����%���M����:~=�:thb'N�k���G�v���0��[����^z��5Ym�YEg���8���^$�y/�~F���
��H4YS{\�K3�MJ�+<���AF�M�Xb���S��l�W�Q�0��0T0�Zn��A���}�:0���H{�������7�@�.��%!������a��C~YB/Y�S��*�&�e0[.P%!�i������X�����En�q�Q-u:����
5p���S�S�|����G��/�%��~�n�����s��Q��,�3��HoO8{����Z�TZ�\^�����'��WX�KP7$L~��q�����z�Yr����v����K�$��	�k:	�[�aPv�6EUK��f��m]Q���tV��-�9/��4I��/?���T�9���V���h=a\i���u������R������z��,�fC�{��xXj/r�LB���>�Q4����KBe��E/������
�5�
-4�uNk�<��_��U� �p�����~���O���W�Q.��Z�&�J
�w'�"<��6�j�Ki�i���V���>���k�Y�-��(�aI��i���4�5�������������.��w���2��I���� ���C
�_zG�}�>����>
�R�M���H~m���
��b�8��S-Sb��E�����}��x�-�5��Oc�
��x�h�]�x>���(�<���k,��T�pP���l}���Z�v�x������b�0�6b��>*z4[:���$$�T��(��,8��w�����L�g������\C�� ��C-�a����0&j��Eh%XTC�������?��5L
������4����*��Z�`����������###�"���qjg�� �5���C]�b�I��f��e[u0K^<$������*[:��@���e��F��.��U��i�q���t[��U���,�COtQ�.0�"QuF&��T�Q�����������$^-scq�(�X�����Wx�\�Ds��u����u�������.#8�P���iD)��\Bv,���h�(H�C-v�������a����P<�<�/We���=,���nM?i�����t���~�y�;�Z0���|S�U�a����
���)]�'�jn�8sF���E�������4V:���^X��!M������o=�F����>h���L4��mV{�c��;���b��B!>j�K;��T���%��j�N�TH��@�8���T#m�~c�go'/};A���m���v�
a8Jqg+-���F�3��?�QfF��,c�
7q����l��`����%�au�:����<Pp

��u+L�dq
�1�DX[t����b�3#�V}�
�_��k��5����g8���lj�;1!A���P�7������Z�����j(2�TY��D�!�G	5!a����z�bxS�%t+@_�OF*�zL�$q�h��;�q(c���2����Y�Q��5�"�)Jyq�Z�����U�Q3�4kr�;�s�Uz�A������%�xm$����|�0c����S�>�j��e>�y��(�HEKP�����K��g��]L��=���C/�u6��Rdj�d'zI/�L�������MOb����1��Z�T�	�v��x��u~q�K�����"�;Bm������9gL��4�@����K��<Z��J����4���4{��V���[9J���i*
���#�������Sr����q�Y�� .]�>-um5V,�l�J�N��PM����B���
VZ]��g��}����}���2Q��/��;��ji�g�I^��PX]������
��%!���
a�[`�p�WUn������]k7�tf�s�]9�R98M?A��'��l�r��S��PU��>O����02��h��L�Y���Fh��a
�i���U���������>���������X�^y�����4���JKK�D*��V�,A�.�^sX-�Nc�]ElaTqcX�-�-A##4�CL�����DW.��vq�r�+��D��
�����
W	c�����Z� �<G�TK<LNa:?�l'i�����xrN�������_6��������sV��7�������������/�p������������K$�Zv�z�.����_���e����9u�R[t�c���an��P�.Z���$"5%�gy�u���8���S����i�5IJ���������4����5'-�l�����$Z��[!�!N����=_<��-����C��;-Z���G�r��
�
�����f����)+�6�c�6���	I2�	(�>�+�,R9
3������"R����H`���*'�
Rh����1�cG�<&{���}��<��-�/ez$r�|��* �#]��*�a^�aJVI��	 q�[Re�`�R�j&<�|�b������l$!�}d�����h�dY����C��Jl��~�G[��-���,�h�b�����������;`�.��U�$�2
(R�uz����T,\�8N���������XDP��AS��`��T$�OY��u�K�l*!�W�4w?"a`S���U�H�=g��N=�4*������y�4�����@��d;6S�<�Kp���A�(��r��z���e<�lCc�@����4t|��9���k�^tV1I�d�u\Z��������#��k�Z,��a������]�?&������I��e�:�Vq�����������X���;�o��h_Y~� ��:u���}�����%��z�P�#�r���,�������B����j�����ARE��.*X�����w�����j��~v�j��Bz��k���`�P��_v��o!�!W"�
Q����!�JH+k�\�M��R�X��>�������X��Ke�X�����`�'{�Q�8Lj����bE��F^6]QW�H��Z
U$���7��/M}Z������e����l���������[	�&���x��++�4���$�e
;�����!mV�"��xg{���������wT�r���o��gr���I*#��G�
�.a����lGB]�Y�*��r�����{j5���9�D,�&�t�$�P�Dc'1#���+���*������(�E)-*�:Cmyr���.]���|
���d�����[Q�I~U��6�%��A�R��]
���:�U�H��8��`3#�����9~�D���|�����F�<ds-�Ys)��u�uB��[��x�x�5�s��#�����{*�I�)W]l���)��Q%�����guk�C]����'Ljr6x��=��h����	�X�}@�R@q��;���9�z\����]3�h5����h����Fit��,���<��0�b'uU��z���mF�ld����A�vJ8�KOTUN���78�F��*{��-�{���2��������a�}��j���.�v�u�r|�y�$F"������b�	o��T��(�6�����tP��a�����= `��d.=R��G�Bl�L������	-�K����.��h(���^��)5�E[^�(�F�Qy�(P�B�=^E��uW�<k@vD�	���k���e@��3�HX�|#���N����aF�����8�p�AM�����i���@2 ���o^�m����2
<R��T���`���h�J�<o5��A7�I�T���wr�-���M��:��(�3&����q�Cz�y�|i����K#����W^��B������nl����V@��~��S��=i�3�2�Q]������V�����E9�r�J�]�n���0�I�k����B�}��	�����xB����<�!�nh�DR���G Y	k�B������G A��(fGaV]w�W�^�����Y$�������I����D!}�K�9zn����/m1#���%����A'��`C�XgJ�����*��"_A�"������B�d[w4�^58'*�F�����Qq�H��,���M���E�G�l��|J�ZiY/~�G�RB%��N:
�Le� �=�E�$�I�J�D%_eQ����2�w���%��DDO�����R���H\�B����m���@���f{fD��J^s�*�G�������s�����
�J����epQM�DHU��ze������3�z��s����"K��K%�(/���7C,Oy�	���h���Y*w����� ���������2�}��@��"0d�i
2%�M�!ICg���sur��U���������?��G������j���`�B�[Q�Q`��`Wh��������\����G�[w����7__tmJ��o%��nL��DF�Q.ZZN$�Y]�<����43V��<p��E]�����U�EM4���	�����WQ�N�q#��XZZ�@�N*�(��&Zt�)�G��Y%�1Ju����k/tBB��_��aT��y�������]�$����~��a*�A ��������.B�I����`����3��u	�����������PD\�<����s���$!*�R�����i'��?-��1�Km(����������>CL��9������-VgA�5�<��t�K� �U�����l���;�z���0�*��SON ����d���XMEt�B���B#Z�<5��<"��Tty��z��0�`�Q����%_�v��se��M�|�^p��������'X4�������|�� ���7Vg�;[���|D����y ��X�u�{K�������Fb8:
=r���� h�����7��
{����w���}�#��k�D�pP���z!o��:��Ka�0.e�%E+����J�qlO?�I^8���s!�C�?�M`����
��m�<C�T(WU��y�I���8UrIq���'�%�i��7r5Wg�$0���`�
������@`p!�9AR�����,����o�z�N]�'Fg{b`�q�8����$&),%�6�e����,���L���jaK���@=����,hX}Z>�yU-�&0�FQ�S�`0u�������~U�"q�_n���
�J�\����!E+����_������<�K�������u4C��?�m�Gi\�������UC�`�D��v?��A����4�O
z������v�9s�8���`�����Q7��Ab����|�	M�c�#-�g�X%l�����f�/�)�/�7��s��j���$mo	T�h�s��v�h�%�{[�8��z�7�
h��t�9?q-X�N���"���+����x���0tp�4�_q�o����EK�y�+���8�[���	�:9wV�b�%��<����������z%-��%�_�0�2�!�����>�>�����C*X'�&����\������}H���D�I���4����������r�
w|�m�[�v��Ml������`�mT$������4��W>�c�����og�&9���J\���tX?�R����`��7�x~�m��3�i��VN�:UB���A�"���@r�^�6yzE(����,"�rwH�����<��*6����)����9���D��j(�7JjGS*�����Y�T��?AMbh.!!�������?1�T�ml��j}�\Z��-g��X�=m�N��A�����B��K�	�����I@���R�����n�G�h��u39M�=FQ�������b��p���"
4��"k>��c���
�HG�q���|H
G�e��~��6U���H�M��W����zm����E���j��-�@}���{����~�X�InWc4���Ak%��lX�����j�J�I m���]���6oh��~L�~�)Q#4��zLGIK��_u����C�D��ls�=0���d�F�h�
s�����F��h������O���N��%=T�?>��G�Q>�0�NWl��������N�������f�}���Fdy�oo�X8�I��9��Y4��:vO?'�����h��_�^���"]t��u�H�\�����<0
D�<TQ�H��~�V��Ty�/�;JM?�ha�:��C�.�8Y
�"Xo�[�g-�t����A�*��+���A4'���)Au4R?�����8�RFuG�*`��xo��Z��I$���]x\KI}!� u��e$H���g@����$d�s�����'�aauWDZ*J�
��4#	�JPF���::��������v��eV�G�uTT�ff��G������^'����H����yU�U�2������p��7>�ak=��h�ex�}�W��&:�7|�8��h�bi[l���r=(s!�8����|��z���v��,�������������CF����fy����q?th�A�J�i���|������%�����qg������[��)m��,l{A��N��/��m��49.��-\,S�����l�e�Xo�l���m#6;D�W����lV
��l�M���������Z����1��.��{��=������Bvb�����u��[!�<���(�n��[�Lb�3d#=#��9i1�z����g�.k��h�=M����9��]��!i�����X�m�z�3���0���K�!2&�
���$
h&�cP�$���m�T2����Z�H��D�G�V�zax���uY?"����{��&��g�i����e�JK���v�M�@;0���zmZx���]-#N��/F�:d�
7Kk�1���4y+oDl��������)��zSY������FM5�w�2;P<*�_�_k���Z������$��&�V�H���e�u18+��0U�����|Q�5��f,Zq���L�cA��zH
�,�jH�����]����V��`1�cm�$��jB����QY�$f�U
��R��`R/�?BR��B,@���g�2�z[���_���x&��EX�2��JZ$�m��tz�����S�@��,M�2l.X�K�*�	.���N\��	���<`	�A���]~l84������H�cy�I�u@�a�r��	Bg%HX��i�z���7\'W%�l���@>��M�;S8o�vf37�i��
i�z��)6o]���������4��l��n�I;l�h��6��muH��hij����i��ij�G����p��ygZo��m��/l���\�i�������YC
��>�iO;.�=�/=&�-����E+F�P�B�/N��&M�5�i�A���y"���[�X1�o�b����(��.�G�]�\�������J;n����2����2sXd�&f}!Q�d�/BB�2x����L��"9�K5I[�����z�F]���#}jH��/�'1.B���{/�w$2ud	��y��?|����~�`D��y���6m�5����b?P�2���h5&��NB	��J���0V���m�0�$��F3��G4��18�~�c��h������#�g��Z��e�Mw��#I��R���}�'�_��y�d�o��<;�[��5�I��W����F���.A@'j�YH�yxf���I/��=�*��d��hu���x�`��������&���j�H��6�����(��1C�����lPXq"������H� W�+��y�A�
��M���6
�m#=c���e}$n�)H�}����I2��N��
���8����|����&�4g�"G��+����� ����S���� *aUFB��Ly��Y�P@Nsh�L���Iu�(���"�-�m����m��w��!
-��u�G[����V� PE���p��l@K�h�po;�P�A��&
�����e�C�����
K���@E

uE�F�r�|�����i�IRE]����8�K!���DH�
�)��W��^�2@��z�u�)O�cQ0ZR�� ���$�����D����?�h��R��:a��b�h��U��z6r����y��?|`�A��>�3���xlb�GjX�QB����=i����
ft�r���iY�-�(���DqL���Jg�6B�K�����VPg�p��("b��C�tS'���
	r���y]5$�Q���)� +�C,����KI�W~� ����R�c$R�|z�,���I�s��n/�)Y����E�v�z���|���E�=�l��b��{6I;i�x�F�����$Zm���vs���h��n0>�B�����D�h�l/��kk����H��4}$�HZ���C�	'����kdWd��dH�S!>�	������g���[g��_z=���.��R�E�S�]�'��ja0+��:�p+%K0}��l����IA�^�)5������@�:u
2�h����N�?wM���L�|G����9H
h�
���{H��(*���I����?_z�Q�}�ei�
��h��a'L��I��Y�qA}�GFo�r
B��a��t�(4��8�:�{7�.�<!E
�
�HZ��A�V����d�� KY��E�UA/>�sKD2�F�O���S�����N>��<�5�G��>��f?/P-"�7)��O�),1��2H��!�w�W)�:�Z4TF��C��h����C��j8_��J}���<��n
��$��&kA��LSi:��Z�����U]s�2n6���HT?C����EP�oy��?�:�[2�,����R�I�y�����o����Q����n 8l$�){WnN�7��(_��|���Yi�-�����t�C��-
��UT��������	tt�t����2�
|���g��`���@�]>�_H�uA�UP��0>�ER'TO�:����8�fb#q��E�
��.��J�6���6�p���
��\���{�$[�9#^x�����UsQ$�w���Qo���4����~4KN�|�����8L��F\���J�m��/���H�3���X��+�N�!�����Tv
U�S�v��Ic����wM�[�x�%�49��8��8�)m�g7���d�����]���M.��CD+N����h�J�D5]RH\���zV�v8
K���9�-[A���tUD�x����8����b0����;�3��Ys(
v����4]Mz$��0�+�Ev��*P��x���r?��_^�Z��[��=�4Y�����qy��u\��tU1����4��4%A��]�����r���u�GZ����uA>|��M930��Z:�Q�Ag\

����@gIFA�����/Q���Q�����*GB������0Q���kiv�9B
��~T+X�����0��������`�V�@]k�0S�c�%��YqE$���Wp�Y��-���Yi�8�t��������\Y�{��h
�r>�yl+�,�������Ul9:�B���7i>��a|z�����s+����R�1=p�f���������1dg�4��(qx(�������@S��fm4n�}���^X�<��8���r������	W���s"���N����pJ;q�-G�����r:��P.��
d?�f���}�5ZC?��<0g����s�����*k/���w����B���qX���f='9���+0�r��7yIZY�����H8�E�v���KzF�^�"�R�a����Q' ����>��4u&Nt��1���3FY�����T?�)I�d����A���Q�����o��� A�	<$��������@��H���@B��q"��$�@�h,�Z������)',GH����ZA:�B��T�-='M���7�[0"=�9U
���,?�r��8,7���3��a:��Gb������n,7TW���i-NT�tK�?k*��$v!��a$G�%����q7x]j>'l�@A�<diw>�g]7r��eW�*�U�dW�/��0
D�B�A���N6��y0�B���!�^�V���ac�,m����|NMTc|qYn���������!�*�%w	���nZT�r=���o��L���2���o����p�j<YjU2>aW����������\^��Hw��A��.r��lyhs|�L%������q��pf��J��K�
�����~+��b�k������QPy?��TT�V���-���=@���1M���9\��8z�pV������l�#!�K�%��E�8�c���K����!������`�"��?�(f��p���F�X#��8���TE�4L
Xc�SS�KsR�1��7�t�=�xZ���"-��~�����::�=��^��B#��A���������C��bF,�����_a2��a������]|h�VT��'�[�=�����!�&?��*�9��^��z��������w��^L	����i�9<f���U[�w4������c���H�?�t
����%�lU����v$H�@8��
B�(c���+���f�I�n������V��U�g�{���$!���i�v=����H?]��(��42#d�D�M�� sTvF���i����l���:;,C-Oe�_��(�(]=cH���n�[uh��9S�D�cfY�8���@1��(%�if���K�:u��+z�U�Ab�7p���'0��|n
�c�S�O]I,����h�grH5�	!e���N!`�	��]�V��{+PM�Y�������;���`�sf�P��������G2�H���5����"�h|_Ho��1P��N�w
�����m�
8Ra���LE��Q�+��B�h�nZ���42�+4�Z������A���s�����A�=�mY������h1/m�,\��P4��������o�Q��*eu��x��X����e\�����ic��hH��2�� �{�h��k�a�C�4����T�`��h�s�>��7��e�����6��
Y'pI���N(4�Hq1�G\��!��0�z9�AZ����U1<��Bb!�,dS�C���K�`Qe�����I�$"=U�%@=���.M�*(+�^�S�0�j`�Z���mI+�k����) ��r�P4�ML��D��CE	,
J�^NY\��D��cYun��������U�d�S*5s���C��$�O�]�v}�$d)�@����������#�n�����$��
�-������T*
�� �/����������%I��NR-�YB��0�����s:q��<��6HX�d�3����:LX,��+�D�p$�	���[���P��W5��@"�fN�s2���q�D:&�R��N2f!�����9����]��|�Dl�Kl�"��rz��K���jHX��3��AU�W�D��Tw�D
r�f,2�G���"y�A�f���T3��#���5�V�S�x9�#����l�_B���Oh���Wix��th_�����_!�O�\��]}� n�
e�]%��"Dq}@,��$T����" ��KVW@{	t�V-����bsfY�d�%00K�"�:�������}�����-Ra�������y���V�9z?^f�6���60�t��7o�l���V�=�L$ �R}~8h(�rb$�y?Aj��Y�i�'S�z�S4�<qY��iK
�m��g
�IT��h����I�k����t��� #�wRQj�{x��=/+��N��\��RQ��X�+N��y��`]P���6$5<8��t-K_!�&�8Hc����%����xF��em'v���EU���l[��.�	oeE~s��A�w1*��T�O�+���D5d�����jt�������N{6��F*Y��k1����{
ie�b����j��)
�'���yF� _~������g��Tv�bT�d�A�XN����#�R+!�BcM�54"�)���"8����Y��n����X�*h�dt�'f��v�; �g��l���g���`����$��&����6 _��!�nC@N��~�Q��b,N3~�����6�����y�$�wY!������[�������/-��C����h�����.!��?�U-��<���c�6��L��J�k^�v8�\���{z�1DA�<N����~���z��0��Fg���I������!���t-���',8��0��� �������������l~8j�f@����f�u7j��"���qwQA���r���\\p�q�i3wDR�%���YQT$+.���";f��\���tN4LK�s�)XZ�����4���f��~�� !$Q��SHA������&���y�+�s�"��7��G�����d`���	�T���w���u�����;���W���,0���<���&�]&
��>3P8`��j�t����DC'��������jQ4P�A�
�JH��l��@�PZ���e��������F�&�o��R%��2�E��@`$�Y�����F��&	*b��������aJR��A��o$�>��J���/����r�V��%���F}3<9�j��k*a�5	.QL���&;�����r-���STW}@�=���0f����R�����z�`lD=�Ik?���!$N3�W���kD�@s�z7����BzMm	QM
u��55��HN��\ZAr9����Wk�P���(p��jx(P�9$l�AI��M�J=L�4���Cme�7j���
��[H����J�S-�d�(�����������u�7�������n�r�d���_>;�6;g|y�@��h
`�����9�h��T�c��`�^MS�a��4J�h���& Ku��j����/As.�6���[��L�{�zM��m8��*G	��4�c)�*O���k���
u����`>,���&��U�Ea%��QS2H�="�]Dh���:<lDZ
�T�g��Z^?mM\3hV����c�|�9�m��E}�C�0\J���������-� ��Z�)diK�kuWQ�������}5x`����!�2#�g%Dv�<�����Q����'�2H(GaD�
O{o��*�
4_F�n�L�&o4.�#	Oo��z�6����g�o$�4
b����y$H���hG������W�$n BZ8y��6N����%�������t,:9b��u��;���xm'���m|�t$\���~�k���AM�T.T|�B��RB��I��@�d�������[�`��eZ^����C�3�$��.�~���7u'���6$��������H`|O���6V�t1i�����fB0
>h����k�#cA�n�j$��>zNI}������tmB2E$���w�I*J�	��,����H�I��$�VzA��C�zE�BUVF-m���q��<6�KkZ�_�H��I�mt.t��p�	%Q��)��8r"'r*z�6�s���#��yYyQ��h����:J�R<N��+�����O��`��w�9K4��F�&9�<�eu�J+�%1��$y?(�B�H�i0�J��"H�����b��EB������Bh�r����ku0P�s%����b�XU����#�q(o�����[��!^�
��'�����a%p�����8O�< ��o�'-��
.�J�#�wx���K��e4�Kp�N	9i	.2��
�w�������zR&_8���a%��3�w��Y�Mc��]Ra������)����N�%�H`~���F7%�I���\������/C����J�A#���M) %���2��}F��pkAl�a�_�{��=W�BW��ul 
}�i&�S�*���i�^J-|LK���Wt/VL:�LGGEH�>/���':�k�,�������Y��B�&_H�VlAu�n��)O\c�������+��x��@k/CN�m����>V+�b��h��U���s�XY���Tdu���N0
RQ�UY�&���!��Uq"������XM�8EI�NUPQ�� /G-�{(���ohL�����09�l
��WQ�p_s�P��p��~����hz�C��*O�E;����k�W����^?s�Z������*�S���K�����uZ�f3�UjK�W)qcI:�:<�E��:���SgA�{���.R��\�q$��no�M]bx����]����L�
�{2���������z���V`Y}��V���#5p-dm���;N
����4��������I����R$�����)8���6J���jnJ������@�����Z-�}�4��7�nmZ1l��+b��fWB��E#�7��&�����R�ICK���u����f�(�tKA�A��qbUIbZ�p��<�\v!_�)��D�7����	 i���>5���L�'y�`�7�J4����!�K^�������^R��Gy�G�h������n}� �j�R"�KP���,�%���E>4m_\�K�P��B���d�1�K���L(��j���Ii����s �( aj�JZ(���D��wq�	���PN�!�`���O�+T����[_L�$sn����h�`���^hv�F�������c�}q,3�����4��H��!=�UO}h����J�X��?P�������cLA�	��b����j��T^��.�R����qS�����G+����������Sk����l���"�F
+S��6��&�i���!��]�]���G�Q��'���mW���������kUX��6o�%���-kk$���G��ypMT��.��q�
M��.a6;���I�1N*�}�������]w��F����'���gEP����o1��]�U�	j�ugi0��?6���'�{��qi]vY��`$�R���3�I%z�\v4k��w�R��/������t��N]W6�M���W7�n��������9=����?���������������?m���JR���S�.�#���p
��%���i�(��>�R���Vb��M��i�5Q���
v�ut�	��r������-�����d�p&Y�]I��b���Ew(N���
���4�	�+�z�������Q��:�K��]k���]�7��:������f�
�M���Q��)�e#�
rD��-u�T����A�D�:
^�QaMp.�~g�L��p�������/�� ��Rg��� W,u}��X��[��=ooN������
��)���<�R�i��/���$0R\m���z�3����j�Z�����]��P[f��:����6���B��m���n,��-��I��v���^��-��y�r�?�0�+x����8�9�	Lr7{0iO��Y�~��7���Y1����dp�����Zui)vr;���0'�!Y:����K9��fo|��%��4�S$"�a�Y�2�]:��H��"#�1�Y��W��W�7k�1��c
���-f%T��������BT#���1��n��>�����]W/�?����q/A�d+�������%}�#���<�;R3�������������c�����,����
�F�@���q2�	�Uh���B�aYhB�t����������C*���b�����������������"J$|v{��<���J2�V�(+
��%i�%i)��9�����~
�&�
�nKz�;R)��)d��RnU��?���j���/?�`��u�hU�������w
DS,��	������a���
�h������������_U��D�^���{*�������N�1��B���P������r/-W� 
��|Q���j��b���P�)�?���d����c�ZI�TZ�.��i����{����F>G~���O���Wu?@��Oe����n�O�s��9������V6T�9x���������/L1T�h�/0�S��T�S����/���b���3("A��!4:K��������2��1�0
��N��C')�?F����4K@]�vb�E�AEz����"8��f)����7y��6�t;�����K�YQy	���A��hY�2|��zV)�x�?|�ZgWi���rO"0���;L�����D��r��ITE���K�@�}�t�K����![1��b���i��R)u#~�wQ��U-�2�����2P�>Tv ?-m6/��@�����)��w{R4���,�,�i�~�G�Sf�e�����A�H;{H;�6��vd}o��%���&��u@[I������m���#�7����.6m',-�8Z���s���'��oR����7�G��	��!����������9w�H8��`����s���������#Z>sH�8w}s��(a|o�.e���b��K�E�h9���q���+-d<��+�h�N���-^	F+:^�kR�gH���!���|o��o�K�����*Z���x���>)^G����	-C�L�,\���i��^�,S��-����t�x�q�lVk���Ym�lrI��Y\�3��������1Z\@c]o)���Y/�,UI[2����g[J�U#i��m�a}�
�z[o8�����~�4���e]o{�� 8��u���"������s�m#�{a��|�����e��;��rw������F����]��O���m����[��g=���(I;�~��/=�~S����1��$�u��N�y�������\4�4��pXq�!�l���Y�m��B�o���Y�(��x�|6�X�#i�6�8pZ5!�>
���ex�<��g�-Yi�i!8�
���7d��������-b�lGK�gc��qf�%���Q�6��s��<{#V�-�rF�"�xH������b�����7��G����R��7^p�o1k0^q������W��B�f�
k��R���4��s��H�7�����7�qZ����+�9�����M��'R���	k�4����$����FJX�����IYc����+���q�e��J�K�����s�`s���;K���%��&��1��C����@c}�����]/i+�_�0�Kc����X���v��j$��rh|�Ic=C���^H}Ic����I�2v���>M���[��<{S�����`�*���4��p\0�T���l�����y�K��{\�����1���"��JIZ��}@�1����x�J_~!=.�]I[r���+���]2f�%m��M9������@���%���h�6�q������92VYK�
92Vo�G�p�o�e��3-d�I���F
�w=g����Z5!cd;
�=�������}��$-^����j����v���@c[o@����z���������j������Y���@�����-�����+0�
.W��CY�;F��d�W	�����MKl6����7I;���.7�%_�@��|��r����h��E~��g�H���VJ�B�ZPI��z$-|�����+�� i1���-��t��W�'i�5�{������X���Q�h|��E�$M��4���B��������4�������_,h�6�~:(����?������cSf1.�lOQ4�����byX��+��4 ���"�"�����S��*^�p(�p��K
�(35(2�$��AQ�B��&�%��}���L'�y�������>c��IZ�kEUw���6���s�)]i��K���vLB�g���e�q��a����{���7x�����n���@���mp�
C��N��N��27�[De��}vb��b�B�'����W9M�F75�8���!���e�#���Q�l�D��>fTSp�+m�tXi����$��8��+�s��v<8=[�f�z��LZ9�����]yx8;4M�-u��0]
g�6��>�3m#b����9����ag�v����N�,�{
As�������;m�P{��9hi��v���C��;m�w�I��q���������Xme�
`h���x�J���s���U����:rX!���m�`+�6W�_]����`'�����Y��R�tm��6�{�+S2h�F
T�"x]:�s��S�c���k��S��o����������C$�N�2�v�~��oJ�\��om��Kj�Cg\��=CC�����xMZ�K���b�iM�������C��
��Q�"<:�^kQ�m���{�����M ����m����E<���6������b)��'����M���-ohIqu�����
��g��m���`_�C��e�O4s8��a����<��6O�2��/Tf�UT�Os=]�)���QX\'M��Q��&���%+[S5���5"`hijK�#h�E��{o��5u��m6�	C��m��.�5��h�`���]��z���&����G[�E{���:�m��8�M�E�	G[Y\'MlYi;[��f+B�����G��:�h{���v`}���ogI���E�l�e-]r~k�8�f�c���K��1�7I��$��w�K�m|1���
�B�V��2���KW6�5�&~����~�4���f]o�P%��=2�����r��>8O�ch���%���Z[I2�E������i���0�h�Vf���kFow�F�q=�,N��/*�YllR�(�u$��\�|�~�:�F�ahkk�6����0�(YZ25Z�f�e6il*���6Qmu��=�
(i�b�����	[�
�fk:��mrIc���k�0>�&f�`l�b�w�l���IEK���n����4�gqmw�<�v��ahba�R@��"%(ZbAG����8�
(i�A�Z�d�j��*f<��D0����+DG[i�3f�v�R��Y�F+e��5�z����)���w�w�g�Np�-��%c�T�R��r�]1Z��fk�E�6��um�XK��F���~gm~���[��������JcnW���@�;�$�6�C��>k[i ���<-�u�Z�p4��3��x����`����+^����������X,�[���(�jaYo(Zh�Ogh�������}�����&}qF���F������h��m'��������ml�*�f���bo��D��w�Mw�f8.,�m��H�I*lU:��(�g������^m���b��~���z�����ah�*�����CZx����Z��;��f�D��E|��%��1�Y�ZZ�QQ4a������/M����-M�b���������~�3/I]$�����N�?G5�umP�SB�tq�	�,��J!�Y�FU �����������%���(�T��&���S{���"�b�i��*RbqE�]�%M�L��T��p���f������o�kY�@�dGzY�M��ka�M�HT��e��H�S�#���E��m�$AQ�����jP�0��:����5���k����� �	:|�W����B�R�W �#7�<�����7��I��s���FI@g��c��QMC���Tv��� xI�{��[pyK����9y�/t3s����Y���\��m9v,�4nW`�.���l��CA�p�������6uh��k*�S�G"���l�28YQ��c�!V��3��H���L/��.�.FN��N�v����zy�����l�$yR��kgb�����e�@�!����{����<9V�i�*k�HKJ�v������,������A����U�����_���������_�P�kL@3��u~f��T�Mk���a
��U���A�#
�}H2xC��1�u�m��!y>���G��V4������#�{VQ{G��{��C�6��!HJ6�����[v�������gf\-G�o&�-��.33�Qh��P�A���	�F�C�?��vw�d�N��L����`�J���S�#(��������y(A�r|�}�z��/���>�&�%������~hw�fF>���pG�}M�d����i��7��f&{2���[���v�8��������D��f�F�I��p���V��������	�u���h
�����}��N/�
��E�;G:�����&���;���p�C���C�s�6�����������A�;yJ>��P��OC�c�����X����"�k4M�^��{H��g�S7�
�*N��.���-�z�\,��C��mS����}�u�Tt��Y������H��M������)���f�
wep���1�����Vi��)���w��0���kf��	�Rd�1%����|J�v:�=T��s9��g�OD�m��*F�4U�'���]o�S�}�%S��U���
o����:L0W�T���-f��`p�pO/�!)�l�bp@�8�������I�~����U�bT�.�$��@P9�
�M��Y�D�3�87�x�������)�XCiV�xh;v��S��Uv�,�2��:���'�s�9B��R������N����l.���o��
i���o�dL�(���2e���4f���4P��B���Q7�L��$���X�(��;�'S �3��1�����g���2W�|a�D!�C��A��m��y2����1��zc;�B�6�o��F�YXc�jT�%c�)Wm��\�< %�A����)����*��(�L��,*
�y�C���\>��F-��������ez����D�4��D;�����k�t��@���1f[�6V�������T�^��	0�� ����x�	\b�&.����s\a�%v�Ro�%2��B�!;�X��~��/��=QA�� a@X��+��/��Q�Y9��r/��ap$F�c�X���D#����_��*�
��g���7T�I�j]�/����DSg[:�j���G���� �SE��\[�Im��b�ESC�g�:}�����[qgvD�}5�!E�e�X�8�;gU\���
�����4�9��1h��n6�-�55o�����0���X�C35�b��.YZv��Z�h+�B���"�7_���H
������K�v�!
�T-�BK��
_on��Y���nF�-����hSo<-�)����[#cvD�s��h��E��I�vw���M����2
����>=�]�qh�2@���o��}MM�(�C��^�z���v�Y�'Sy8m�0S���>�7{���L5B	��c�>��"4���78�f?���9�"���a�mA{�?��zg���l������;��h�zy�����h��FZq��}[��7;��h{�H��������&Te`��a�/h����R��!�����(�����tg��G�}��o/��w{�o3�������@{�{�#oyA�r�o�=�}�	%��h_n�w�7{"d��63�����{��]n�uE��o���8��2���~�������no���!{�BQ�9h��������?~����yx����=�
����C�P�m��s�C�e!�3�O��"5+�_�O�<G��xw��?�-��=z��,4�n�����l����&b������?����m�P��E��l�*�u��r7Y0Q����d@q ����<���*�,�E�_��x����0Z������#R)qM��=	$���J^�y����"��I^T�}�P��
��.C{!L�8V�A@��������O����3|���/���'�1�����~B>���?�����HW���i����������������G��;��U/�\��������Y���zN�"����o����^��y��/��y����;�8�h���{�K����'AY)��X�������~4A|{P �)9�CqH�����Z�ow�[��|�a��G_U���E-�m���H�O���$�z����q��(M��Z��e��=��������[��wtw�@s�(�~c�c�C!�6N?	�.�?�*?�zn9�h,��i���I	-=W���#����[��U�	����N�8�����Eyj�4���������3�M��a7��%�~��b�l��Pz{�������t���9z��[�n�^7_P�����P?�'��t���'/^��e0�� �X���o��l�l��((wC�[(����o��ZB����F���5
�p������2�z��{r�l=�X.W�R���E���UW�y����9)��J��s}H��ca?�>C��P'�������a������,1��U���~3����	~k���d��y��F�+�^w>rn�p��Z�}��7�����!;�;�8�WQ��>lP^��.q��=+�����M��|���6$����f�C{�x�7c�^
��n���]k'sn���Zx�r\�3?��{��z�n�6(��[���^'�D/*�`���E���L�xe[������XW��%�������P��UG�(P�5��f����D�6�U���o���u��s)�_5q`��*���<���6rDle�L�@�+Uo;I�����&�k���L%y�Y>��b��m_���pc$����H������������X�����z(W�����nn@�U��D(I�:������u3�Z-��lK��`�'�N��_p�6�X�[�&8��"��+�����9K��"���u�>a���-��]�1=�>�����!��c>
9`���A�E>)Z��I����-���f� �����������J4�8��u�%�g��(O��u���N9x�s��*��],j�8�.��~�+Q������
pu�1��=o����V���^��������*�m�	�y����>��,(���*�J�]���ki�p�gJ�h�E|?8�G��Y��x�TW�+�S8_	���9a�����/�\��
�>�n������i��\��}g-[�^��-tX]^mB���R�_mG�p(;�<��:�v��ql�nR�LW���X���}C������4.�>�k�0�����������u���v����"o58\q�����
�_�>������x�p�@��/c�`���_��z�X���j_��G�_�Z����|��T�jc���`������P{O�Bz��+;����h��8�:���Y&�Ls>�� ���s�����w�������>idt����������q=�1�)��Z�Kw�W��b�y���C�#�����Ay��V����V�W��#�����[(n�{��^d'�fg�'�38X',?`#��ze	
u1>H��WZ����U�s��d/R��I�����I{<���>���z���*g�?�*q�
����*Og���L��M*�\E��\��M#���q�q�ZB"����s�+T?����D;���V��F:�Q���0 \�oh��[�W	`]S��!��.Wz����v��=P�PS���]�g�8MW��Y	���=<�G���B����U@����<��,�A�q��#0��#��`J����D&���f�*a6
�g��O��,��/q�d�`��'N�Q�����B\�?� �2E��a���t=>�#���I�\���	o
�~��*��sh�UiY�GJ�n���h2YN����$�K����<YG����IW��l�{3_���[�J���"��W���t��T���9��&��%5W�A�'�'�1�������9[*��3b�x�����&�5�5�W�I�h��%L�����MV�I�� �%��	��QS�����s�x�����q��<tv�r�yg������)`������Kw�� bV��ia��27�r6�_O��%W#�Y����d�����r*�P�)�n�j�-\��T��d|�
MV��(p=7��r#e�h���?�X�a�]���oC���@���'���\O��?�?M�<���V���������k������-X������/�5O��X�L��.3���e�I�������
f�\�^����Ge��]�"M��y������L�"aI���0E	���'��29���:�V���������*�)
�� ���eOp�a8�}���j0���pI���)O-=]�(���|uN��7����e jg�}���i��^+f��������B��)P!��2������pq�6�A�oeQ��e9w�:MYO�J@#klZ�~�lX��$"��r�!F|%�-�u�{�
�����Y���
�S,=��{�:�CM��������`IF�j���]_(�R�tS��5����#���v�>�Q��"�!=0��6Yw�g����g����I����?���Y=<��Cp�����7�hj|������3����>
�Cz�t��*��
M���|\�.��d�&��A��5��@��<8-<�������^,3L_�������
���������J�����M����9����xZ�Y�.�v����w���#3���k�x���\��&s6 2��*!Mq�S�/�R/����o�q���v��z���i>�+�Qt[��iGS���P��a~����8�-4�6�������pMj�=�W�I���W�p��Z���9cg����U���p�u>��^��le�����9e�8��	����"�IK���Fcv��/�:b�
������_&sF4��\�j����k$�JE6���]wcw��>,
!3oC����dnb��xv�~{�F��|�w�]�;U��wO(������������!�����E7��e
���%���qX����k�gM�I�������?�V�(�@���8��;�"�i��o������(??�^A%��b�u�l����x�FE�8=	3�\�p�5�1�P�Zt:B��	����s����B��V���v��Z
��(�����d���q���k���~���
�5���E2����
"������/�|��U+�+�m(�mem3���\6�WN�aa5pa1��^�*FNa+NP��:b����,����*rh��.�
�9������Fg7���"�sE�d���X�!��9��f9���C���<�z����}��p%��{���T����My��k"V���-�QP�:��*+�Z��S����9G&��6J��t&�%�������T�����t��9f��=�����b��|�����(��Y�fS�o"��4M�E� ���z�.26k���Yb)�����CUSB0�"���~���+�����i��)����-!����Y��i���d���W��m�=9�B/��V��3K���#��(�A_E/�	l�E���A��-K�ydY%�����D��6
�
6<C"��c_�o.�?����2�R�M��V9������.a�����4�t,Ed_\Rf
�.�����ne�����pY�tb���� �����AG}�����b;u��������>z����:?v&��o^KE���v����%���s�#�<�x�?��13�d(����\��pV�^p�9�A���d2�#[<��J�r`�o�0�\s����s}h��`��]��m�����"g�6,9d��P���%�!�w�\�������4fx�u��cI{�������K*����&�
R����6�����e���-���L����=���+�k
y�T�d��Gr�����,~��Y�n��y��)\T�r$$"9:����8�������e�����:��
uwh[����Q3��j��h,3#�*Tp�('+�3`�+:��y�d������GX����r/I�����k�p����Y�'.��p���}y|OR�	��O������Tr.*|M	1s�B�+��2����MC(����7���Kp�a�y�o_�L=���,/���a��h���
PtG�t�����[���"���=*�����(8�U��B-�mc�^�$�U8�
��B4+�.c�.�
�����N�����
�R8f&y?Rt�"%���m��T,[	����5"�=��E~2���[�����5��mk��jR>����[��^8>�E�Fd�����v=���H��a�>����*�b�T�����}��\3k���Ki�v_]8�L�R��Q'�<����(�����u�t���#:	��������r�q�X���8���#�#@�/l�-V�`�	��ya�����[��i��B\���,2��)���,�*Ph��(,@{��0�:��o��p�Nr���F�������1���P_�KT��Z�[��\�G�J��`S��kU��[
�&e6^�iU���������|�~�_��� �m�`QO�P,�q����h����`((���	R�-~i����35���T�����t�q�����{*,�z����Pq�Bj����P��;��9�u���G�����0�_k�(OJv�a�L*�{�$�v;pM�6;�4��Z(J;�1v����c�g������ ���MZa�#t*G�K��d]�vT�X�h$�� ���Z)[h\����l-�Kn�<c�$l����.��x//{��W�|_����q(Os�N��}�xN�kc{��I����������_��p>��m��vL����/��S�|LGu%n��K{���]����:��k�	�\��GI9�����Q(���?���G#���5��9!������Y� �H�@�e�
�^p9)���p��"q.^��KlK�!VVVmd ������f���������Bo���c�u�IOK_�[@��A��10E��Z��_A:;�B��]sHE���VZ%$�D{��������>�2��ec�a�M� �������9Q7�-�&cvo�.Z4�{�%��L�<4���v��4�bU���4�R�!���1G(s��K�����f��J�u���tT�K�?���u�	��.<s���i��8J��u��lya:
%�Kf��q�)�����h�xu*H���c��yFYs�HQ����L]�!AN�es��d�A�*2��p���=F������S�����ct��/�F��y:��~7����`(L��/�#%=����O�������}�>�8�:qR�2)�$Y�!Yk�'����d��3���"~
*�,�-4jC��|.U:���+���T��G�[�S�e3K��$]o���]J�b�J�O��B��z�6�Z�R���LS��;/i����8P����{���#���A��7vV��n�!_E��$l���g��*�<�����[P��������T;������1���4��Z#���B�$���5����_���h�����=��e��w��<������>�C�j�x��}��$���9���M�Z$Z��Y�<C�Yu���{����Oj�}����%������y,$zJ[���wK�82�3o-I�S�P��LK2�P��7 �9�$r^��4k�2��b>�#�r�r2�e�����b;�K�dAj[�����2�#W{��%%5]B�yA��&kX�}�iq0�F?�J�Q�6Q��,������S���^�8s����B����6�m����S#Sx�K>��<��)�9�DH_��;W������ZM��AN[��[v>%y;{��0x'�#��	��K���\�����'���<���0c���4Fm���j�)������s��Ex����a�5�����)/�<x�v������>ef����s����^G	�|Ji�����lEIi�$����+�6Li���^������l�Pn� e�St2z����(�Q+r��-��~2�5�z�gN=E��m�jM�P{��h�i�"����;��R:���i����;e3����']�N�x�G��R@S33���Z��a��E�v��t�z�DI��d���%-��U�����Y2�Wl���n
������GyM8pr������S�������f�hQ����`��rn ��e���)d����D�+���Ng�W�H'#q���\�� �&�.���T�h���_�4fr������t��}H�[�iddo>��Fw��6�mo~K�w���6V��fuL�7�E�0����R��$1�8����4��la��I+p^�B������-�@��I�TQ�^H������Qs4�wV�f
����#��&9�,��@��i^\d?f`��T$��D����j9.Y>O�;!Ir���a��QV)SNj|�pRJ���J����E:�~yx�!�*������S��t���������~S��:&7���Qo��J�P�x$�r
{������[F�&�����!C����
�b�ET�MF>�����\z�����?���&.Q���]�e8�A�s������!W�G���_B�F�R+����4���=��}���NM*R�����J�,������YFa�-�q���|j
��l#��'x�k��������9���������^�x���t>N��l��J�(#�,#L
���8��r�/t
R���CJFr�]���FF�S��X��De���K��p�f�����M��q�=8W��Y���R"�P�l��e������hm/t������������V�
J�Z�����C����C:�����t���ps95�|��h������~��)c_��2�d�,nzv��qMV��&��M��}9��>���iP�<�bB!�7�8�z�;G~���9^B������T�J��N�e���dM.M.���J�v(�h�{p��v�3����f��,C��1��\����^c4�z���F ]��g1���V�A�	��r��|r-�#AJ�
�R��������:�N�j���W�I�/
i�,L,G��,?d��y�pH��H$�^h^vF�WG�WK8�4�d�c�mN�T_[�R=D�tP����D(�l��d������b��!K��.f���Q{���L[&���P�:*����x���?0
iG�G���LB��R��qi�6B[A��~�a:��<\K���F_��+AS��L������!=�	n��Q��o�B��C��&�-!~�|�*��M�q��{�	j�
� �#�9c�b�	 �����+�'�n���;�<��A���+��-�������MLz2�	1+�o �~�x�HZ��T�	�<�e�������T�g<�|a0��|����m9jk��oz+GNi��bi7�Y�i�T���V@f�oG�T�2W�r���D�E/G��%�FD�Ps��sD�����$�B�*�BU��V,�?1��A6a�&
��4�m2+��|"P�UV�o� ���*���/��.^�WKv!�V#�2<��������	2�
�D��u�&
v��&�{����F����d@�Z���)�<y-	Tf}��]	ElJC�
������:K|������
�k��2��q�:Y��|�W��#�������-����'C�x�?t�n��3����
@�=-�d����P��,�_QkiVf��;3�Y�����Q�g�@]���EM�#�8�r�����s�x]�W�{���OUO��tHg�I�9z"��m�k�w���-oGf�lN��Ul��8��!XW��M<��u<��d��gSy�;)�"�gQ�j��Q`B�*�};VV��
���~~F��-�J�����P�����3���2��z?��0�h�����!�����`�V�L��"B���d��T��:S��|=��:>V��J���K����g6\���m'��1�+���\��S�=N���Y����+d��%]���'A��?����9El�P�A����t��5i0�:�"f�-Dt���g�q��L��v3msY�p�{xW�tkd.������B�KdcZe!L��H2��-�5s��-�J"M�)CN����eH�Q�M�m��G�^E�0z�x���g7�z
-I>B= s���4/z�vZ�f�����6�+�s�����D�2	�y�*9���4������8�k�{�u�U������x(	�`��e�1�;�FHk�W�y��OZ�4����0��s#�`�6��1�MV�Y� A��?gQx�BP������7���UqR�f]�^���U���EE&��3�H��H���]�`�h	&�i%�C����vf�l
��(%f���3�MiDj��;*:>���uF(#��2���m5�(�dG�v�<��dX9�2z�W�a�v.���t"����k!
+
&�����K�w��������E����������� �NE��,��N������O�����@I�-F���m�4����D���
��y���z�s�Y�@cq�a�����>��{4
�����`����������F�eP��_�W��I����k���P����1�0���5��h�U&���R��M�jw��<&�d�L������*�����;u��������K�N���G',�z���=���in�|wJ�����]����t�������cd�u�Q�1v�e5������Mg����-"#�PV�M!	���@�Q^����U�;V�2������s�8G�Ne3n�����fC<u{�z�25���6c=��f(���tE''d@�[�&���� ���9!��D�
--1=2��v���Amr9t�=0���,��d(��r�����������ZpJ���p+I��C�+�p+A�E�nS�����?>����"���BQ[�|lFj#C��
����'^��"�e%ZWl�S���������~4�w�J�:N]N.�7b�����{EL�hg�S"G�n�G$"��b	:�Nis��UqRn��	-/��H���dAX�����>����=wJC28!��&��.l�f����n� ��Fq���f-F�e�����MELt�����w)8�6)[S���8t�����J:�%
�1����@c$��`�r4U�v�|�E�6�_R�Q��
������K��gp�
9��0Q�KAU?�.�@3�������.'��1���,���p�`~r���Y4���K���@���9M>:@��4	�o����im�� �)B�k������>�����|��R^���,m9�i��goA��v��j�����J����0��a�h��!����������d'�:��h}8=�XN������H�D��$�����������)w4!��t���G)���t�b�`N���@�4q!�8�,�6'*H
3/^��\������Cl�Z��q�^*�@����0��,9U����L!fH]'� �~�(+$]����
|D�� ����g}n������S�3p�1m�/C����9NR�h1��=b$"������DS�K����4W�d�oY6���0���N5h��!�jiR�-�K��S��BH�*���K��L]��������b���/:@��z���:����k<5z9���#_Y=�5{3�N$��
 B��0R:��<kf��������[�b:$i��c/u�S���9&s�����C�u���	��L	t�c���=��Af��A(�V�c�
�3�7~	����D�N<hZ�6c&�R1�b��zV(�����K���V;��bq@��X�cu"J����X�#��a(]�����:\��W�P�	3D4{���12���d�1p��Sb��$�PA��@w�z0
���!�6�����1;KR���e����:[?B��w����K�[�����Y�@t�.6�Xuk���*r=<�k��i�cs�)�G��b�J
�3?�"�Y!��u�_kN�YR^�	�tr���2������Ep���^�&R�����jtPHP�MD���XiT0G�
�#����"6��4��cd��$�,���S��Y����)���>���T�M�����T��'��U��3�tDKg*�s0��������Sb�V9������?w�����5�@���l(��Q{}�+w|���K]Be�|��'!���1��1p����#�F�k����n�p�H�I;X�X�t��|%c��O�����i$���@�5�xm�K��=P9������Oj��S��B;���n[�Z�o��Q�����I:���J����S�fVl�U��M��:�UV�
�M5S���#;�A*�b���` ��N��h"���48����'���PM��N��2���x,���N��.��$7��0X���$d/�/�Dg�������+�(����ro/Lg���E����lB�%�T.�&�<&�VL�������c��1M���1��%����-��:k���LM�v�V�3\����U������@���`�:�$�����'�D�GH����B��F�|V�/���b�P����+��"�c�����v��pl{����rY��N��o���25Q��PQ�2��ET���6b����%u��O_�"����P��P(H

TP���0���QU16%�� 6	���P3Y}�52���BzN���n^?��$��7�*������bk�SQ���i�D/���jyqW�:s�9��giU!��+��*XB�s:����))K�&"��f�3I���Jo��/&hCR�.��]v/I=�(�<���7��@V�1J6�����\�BJ&Y+���/��%��Y���iu���&���d����y��U�o"�������j�^�!NY����,T�mi����o�M:�{����2e$�q�	��B~$��/>��
s	������7��q�d�r}F�:�7�I����a��3���>Hx!z�k�bO��Qm�"�y�J���L0_���cTe �Nd�Ee]o)<s�~m2:��mJD9�H�!��fcH�k�����i��]�N�y���/���L�!	�I{�My'�MI����bDU.����V,�Fn$��`�.)g����@e���];��Q��w�o���6�m��nx>n������%�����4�K�bj�5a����%�R-�Na��>d���72��Z��I<��t<��#�~3�6���Mu%�=���3����cT��[���g��qdu���OI�N �;Z��Ow2��FE"HQ�`a$�����c�mEX�f]'\xr��d��l(�2P�
L��RLD��
-��'Y���Y��$�sG���2��;������_�pW
pc�4)�����u�K�Q���~��H�\rA�5=!�����7�B"��tNl^dz�yZ@���n�8E'o6Z��
Qn�Z��PM��������!9?t<
����>�v.A�W)�Lw��(rC��n^WV�u����RG`b�;�,������p�/�$���`.R��M��M3'l1h*N�����SQ��+-t�.�\>T���K�����q����1<��C7�\
����5b\z;�G��KAF�R�0��&������2��3�w���exN�=�j�RK��cW�0�J*J;����K;�y������������������r�c�����R/�0R}����x(OI���%KM�^RH�����t����w��T=U��FK�H���J��#J�������Xg\=����&��av�s�7���[�q��PA���k	�l�DPg��
�[PAVu{CSA.���;��T����{y��(�������/��o��E�Vt}�x�u���-]�()�R�E�aB��~&��Y`H��h�H����X��q6��O����K����Q�C<��c��R��T�`�px8~N$�m��r��whp^
)���T��!8 R"m�� �����v������P1}�x'87@���9Jt��SA�������4��A����>~)�q���`@vC/C��)�����z0�zJ�y��T�Ent������� �����(�\:0.��F2�F9�	�c��@��']`� yb��*BR�3=�p�f�H�)F=]�<�]!��8�a<%�:��f":�FJ�!�0��z���%b^�����eDS!�����D!���C�.�J�	�j!����p'���
"}1N�l�����}��S�_ ��):	��F����Z�2�[�R_*�m�;�n�q���T,2w�����A���'����G=�4���>}8�����8�U�S��C����2�1A��0�*�������a�
(����3�d���n��$E*��:$(��	�4^��!��k���c�20������p"�BO.
K������Y{s����NQYA����<�v2�a��j��_P��-�2��K�,:�(�"��������;��I����0`�����
����d_q����&���r����N���9���:�)�������R�{y�)�r_�Q�Nj����I���r0]�:iX35���y!=D'e��\�LN�;������k���"�z�c��z�:�P���
]%�����Lx=�A�gT����U�y����Z��,�$�I�����8b]���p����0@��>:#d�\I2��d���3ID����m�0f)]����--�+G���6@?�,������d�}�XZ�y�B�E�/F?��8NF�J*����
����e�r]��,a!�����r[t,��1�]t�,��%
��*�-�E�r��C�+��H�^O�B���-zP����"8G�7���=3������[��(!A��o_�>�~������2,�V��b��?�2�y�\���%��Rq�0���`Th�zgt4��������h�s��s���y�tQ=]�^,>��T�7�r��������C�be������	:AT(����`Z���2��r�a&�Z�Nz)�IK��z=�~�R�z�`�����A]N8��s�C� �]�d�^����L0�X�IevU����-��35}[]�;���=��N������(���O��w{����i���M<���H� $q�0U��J�$X��&�Q�V*��xJ/��7T��#8a�7��� I��C9Jh����>�8�*�"�\���G"�$Y�+_���)�t��T�����e��� �P��nr6�*
�%�{��k���Ly,��Ok�U #�C`��E�� ���Ur��I���P3A{�
U�/HD��O�O���T8;4'_9��ZJ�t����
B���s�%��GK.����*Xh~R�9��p��`�|q��&Q�8d�t��,�M�y2��A�
���"�Y�+T�K�����q�JQ/'��l�
�(�Y	�p�,��8�M�:@p����k��AS�gC~�S���FwK���������e�����K�Z���ro��
�3���;]������t���T��9X�]Lib������@v���=\K���If�_��3�(*�4�l��f�-S WUe�/ji�e2�b���<��y��g�� t9�).O���F���������l���������P�����MF�C���-,�� 
"m�4=�"L�A>|{�B� F$�}�.�/?L�Oy������lH:���"�?�GE�o�����������P�Rv���*�r(
ab*��G#:��iQ��K����69��P$�2����B\fM��&���P��*z�X�{M+���b��������z������p�A�J�P�6�ndL���IQw�h+�E���o��7�����56�R�)��W;�Ho����DG��pp�����m����{0���T]��E3�BE �:*�6����}��O��I�Z�@��v�"�Rp\@��8U�l�-HU�A��d�)kM�l]��!xA���)b\�������$�(K-F�`)�0��f1H)x*��!"��D�����a4�9^(�������-}Nf^�J!4-'?��3i��L8w�c����9�Y��4��?���ZT)e��J�i�C�tJ��:��*�&�0�[y<��t=*���'u+�9�F��<�]��+{��x�0�U<�0�?>���!����+*��V
y(,L�,@�_��M)H��a�2��lG�'�,���B�[$hV������P2X+S]X�z2��<�8�JYV�W"��5��c���u:�o���K�>X�>{��e���&p�1��Y��m����a1.^|���������B�@���["_��d�\;H���DY�V0�W�C�`yf����s��5Qh����}`B����N�9��~����S]�#l����b���c��cf}�7�];G��1N9y.8���noa2&o[��������z?�r��V�jz#�>�z �����"�x)3����b� G�36��`����9K���)�W���o�� s�Q%�(���<L��k�A����b����Whj�'K�1,��"�A�4�f�s�@*�3{� ���6G�������}�6"�)OU(����y����q�� $c�J� �jL��'CUf2������)��."NfM�g[��
�z�#�3�T���T(�O�s������_-�&<��([��(��A)`#��lE]4��Z��a�������^�V�hV�e�k�O8Yy-L$#������nx�[5y:�vM���������*����sRz_����\&3�C�?=���0M�o4#D����zj��'C*����C��!vO��Kt���p�7]Hat�t@X�����0��f����B�����	l*�,����v[�Z\r*�O�z�LCO��h����CH�����v6*Hx_�}���t`����{�7#^�"��m+�_NZA(�)��1��:�A��|~W1�H��fvN��I�v"> ��,�D�n���l�2�e+�|���������5s"��}L_Z8��������l���
At�l��K�dT���y]��6�n`���v�!����� A0����;�D4������X�a��l8���#38@�E��8�C���9y����yO��d�#�hC0�]��A$���*H(U+[j�m|��?@�	���St3��o�-�j�t�$�j�iP)�[3"�0��<�t����(|=ze����LeKbP����2�������^'���0������z�����(��\�~���;��6��D[��|e�$L�M6��3>t�\S�J� ���",�.Eu�
7*pz��y��K�[��P8�we�3�8���Y-%�x	���gZ�9����P2�O	���}zc��Y �2%
r�yqt���Q��<�����B%e����EEJ1X�b��2����]�d���#Q�@p[z���$G�`���!#����q�������>���IM�4@�y���v���r[I���ag������ftSn�����=�,7�y$-����a<�~i#������=9�%�@��W�W�S����h2�Z-���0
T���W�5����)��A�����t�r<`-�f�g����"a.��F���02@4u�l�����l�[��7�#K)�H'����u�n��!��l�g�W��]����H� &"C0�@�Z������j���;���&��H4����p��BG/)Ik� �Wx}~

J����$D`�N*6����T~����7�U�h�Q���J�6�X*���<�C�z��1:H���WP����	���)���	����|1\�C��Z2Ut�U��S��5�h�!V�W��dc^d����q����	yt�
����Z���aSa�����ox�Ku ��5auCX����G#�bX����A�=����Qa�D[=�GB����L��[��p���Z?�N�g�dO���K�)����T��ST6r���S�,�m6�'AO����|�FC�,	4�RC#�J�g��C���,6;�
uy�s??�^0�Jr�p������vfWb�@u�|��85sg>�e`��=�s����.|0P�0[jc�*��-��Dm��-&|[i�9���_ktp����a���S1�=y���x��/��g{l	�g������lB���0����3���%=����k�g�����
��JR����r��	.�>#�9X�C
9�����T�
�����y3�49Cm�f������f�B���}]�I����o����T�G��Mmn{:��c���O����M5G.��hy$!����;,�G<��8*/�lc[�o��{I�y�\8���Mf
H���}v����&��r���C��2=F�����
Q������R��UfHC��J��1��H�����d�����^)6F0*�������B��\_��"�#L&���T���A��1�����C�nCx����{������S�'�:{�[�Ut�
��+c�E���8�*��X��� p�n1D��)�T�3v���(��qvp�V�d����,��-�I���v8�����)��r8�F���Kp�t�`c,B9�}q�\-���ZssGS �|�ZQ�j���4Ey:C����l���`����#�A��G�S��4,�8�����b�W��m�D�}�|������@�P��b��I���2�3�2e������ C�}�y���Q.<��`�6	+Mh����B?��5���� �7���2
f��F��J�N��B�����D���L��ac~���y��L��U���kZ���	S�	h�}���?��]bi�b�N7��a���~n�0?=_�I�����a�p���������������W�E{DRx���Z^t�B�b���kiV$0���:&Pi��Xsc����������Z���!�rU$�8�&�S�P�3������>�~����?=��fqpq�!��!����e
X�.�P`���b��kd�qSFFf�f���[�D��N�pX��p�fa�3��;�YM{]�;L���0�rn�g�A5��>��{�����z/�j���G�?�$��������PS��cS'����aU�Ws�v������a^�'�`
<��w�G�P8�j>9��pr����9�F��fP�T8������R�DX�:\M�����}����D���C��`�����5e��t��u"���|��!�[-
87����88|^��~�6*�z���I��$���]U#B@u���97�����o���a�YR./T��' �-{�B-
5�+� GowDX�6a��&�R	��M���9��n��+� '��u��*�����1O��j�x�'*AG�9`BX�R��u�M��L��bjG
o���1�=@BE�Eyj�]����TSI��E�bF�XK�<43�
D����Y�T��C��^�5$�! ��<��O�m+LE	+.i���g[����OS:�Q���{�YU���K��z���r�%5����TO� ���9���c��������|��p���q�^"2�����_�Bh�'�5	�7C�a8��3�3�{����O!��4&y�
@][�ps��}��h��G��d0O���o�����5�A.�qE��e�g2.�FZ�����0��7��@@�Q�����\xy^h1�J���{=���_~������?���i�z���u��/�)����UEs20���9X��q�}8L;�?v�
A���k��P��!� G�)M~bK����h��_�!v���U��2�c/���t_�SfEn��
�(��F�X���'�"^���������O.����,�l_��+��@j����_��<�)2���4�c����f\��G}!?^��a��K��y���/j;6Dt��Te�����h�t>��Y��T���,����5��[ff&��,�*�Q�r�#w�����e����Q� KS���3�2{rA8�3g�@J������������!9��Y9�u=�p�\����`�3��E0�"�����c(�T6�kK�z��ka7"��#��o��`��G��K�G�'�w�r8�k���k5��\%�9EE�/E�^����@�b�e�/W!Dz<�tpXss:��%6��S���,v�����f���k���������Bv~��U�}Q%c��-���Zp����SZ�����W��;)T��6��f�h��(5f�-����Rxn/cvn4��T$c����O*�!���MZI:�9��`)W�St]�e[����Npp&o�,��!��L���T�������E[��e�!��A�X��d�I�/MZ6)���1�}��=�t�jL����� �i��9���\�}U��
���z��"��t���d!R�"rF�z�E�
�`,��AzJ"27����d������1�/M�Ww0s�e���:�
&��B�ql�U���R�p���tr�##��
YMM������]#���To3� �H�8Qy��Qr)��Q�BVe�X��+�b����FE�.E��5H�����:&��I����KM�����@8u��!bOFYM�P*�yV�p���Q�P�Y�
���dv�_dK�[��4}/���s@`�{��Ur.O�uW�Z.FX7�u����"�����d0jLf#kt�"JG8�K�d����t��"i������, G�#N	t�&q9a���2�7���������J��e����/�T�A��6�\��
�1�i���]�(",��Y7u*�EF|%�<sKIz��SBOZzT�0�!hZq����t�d1cgEP�Wk�8�pf��8	�c2��i�l3�0��8��~K��x�)�M=V�����3�����T�zZ�����@M\]���1��|������rx@?J�M�8�
Fg=PF1.���.&2�c�&�)�k�i0h�����#��q�`��4���V���x���S��{1a����G��hZD,�+1�
.�y��]�N�5iH{��a�}�`Jl��a�pl:��s;��]���v8 ��ud������$��������c�����������~��
=����X�a(�S��@��wQ�w�<d��9D\� ��:�W��� ��tE�
�l����z�}v���!�S���#��Z�s��1�=?�z�_���{q��^��S���9M���p��A�����_gMN�%z�M�%��x�����i��u���V�}�?���(F�uQ�1d�*O
T�,)l2D5��01E��N�9I�@�]��ie��
���)�)���kf�a0��/u���� <�� 1����o3	�V����!�H@Qc���q�z�����qb\�5N�'������^e|�L�(/ZDn|�6�U��W��>�-^�bida��9��\���Y�vT��2��([�����Z�����=���=����H~.�G��1
W~�:e��l�>���/������9�&�W����
����D(�r<~��`�����_T���$6�@@�8��E���>��X�r-�.�����P��#GY���e�}��0�~D�Y P��l��0AT(�T*��
gu�Q1���E���������1��D��R��e�&D�������[�!*�	#���U:"�Z���U��A����t� !kxoLu2J����l#A�^�<	$�z)�^^��e��h�q��E/��~>dJh����}`�{��>�\��cQ��k<>A�Mv�_��
����.�h4 "�u���'�br_�8�Dspl;F�X&��9���w��F�^S
��o:�z ,�>e"�pn_��V���)N��)zu4�M�R�<�b�P�z�'1��b>��@�ly�X?iO}����T��		B������%mD�P�=X�����������k�j�e�s�Y+2�����}�*�rJ��/���z��[�fd��0^���%(-M����N��_��
Z?��&$C�<���%�nn
�Qq���?�v�!���`�
����v��#c*��,/��g��f��#GMF���[Z_��n�O���[���1���N��Q�#��{������:��O��V+6������#\D-�m�*;�.pP�Mv&����0{�%�����\e�"����r�MZ��1������7h��(fc�\�2ve��V,�_��~�ol�j��WvS��7S}0���KC���~fv���_�`�@*���W��9�����y���45�N��[p����#����qJ7��VA�Q�%3�|(�"$
 ����N�d2i.dP)*�����)��J�M�2��F2
�	�SF��P
 .%����J�f7��1����A���IE�u�����b�S�A���H�.M#"�fEy���N&&���x��M���x]���*��W��q`q��S��^�#��J�$���+}56ZO��*�
xCYF��N�2��7����K[e���;S�-	8;���"[������&��]���uEc��0T�[�������[�B��|�gR�.-��Oo/�(�Ko]�qe�PX���$����������g*��C���� [��cL�=N����>�Vm���Tu��z4{��x������,q:B��k_:�>\�a:��]8��	��~����}���������S{����OT^��UK���g�/x.|�{����P�=<|���������z�@������B���L��9����_�)32��{}h�O�_
������w�?p���/ug����������K
��>�|c�0
�wp����������}�-��D�KP�^]�B����g�q�>?�RnD���?5���4��|�\O}��$��*��ia�K�{!�$�\�A��`/��4���E�6���C�}��b�������;����-9X�g	:B����?�?F|�:U/�>S��G��������kx=u����{��������G}Z�}������w��>E���9�J8����#m.G��W���pM�����������������������O� �]�Y��}������_ML�Oe�{�J�������Px���O�����,�����:���������m��;nnn���	�����������7w���?��?=��_7����>�?��O7{<`��a���<})���S?v<n����������w������CW����s�;�3���tC�'�&��Ov�~��??����������O-
z������vT��m��#@���r���<��U��Q�w��?�����E]���f��e��eU�>�~1\��#)I��E�*,�9�����E���G���G�8�^��/���r�80�(��c��!��n�dS���(k����.(w(�0k���n����O��B/����>�p/Tgm��2o���������Z�Cz�����b����;�K6����>���PTh{����(}}�@�/}��^{0Q�R���i�M?a}�����������=������tQ(�U������1Yz�/����T,����w|,O�����G���������>�Es��9�]�*�\q���<�j�XM�~�,x�����A�=���f@��R���Z`�����Uy�~R�����~���?>/s���xF����o@"��Y��$��'%p�����|<U�\�~��k������w���H�x9�����
���s��Z�;��Zt�5A���Ia����>vA��<V�p�qW�����c�0�f-
8A&y�t��>�<�*�(It`??�>�]�Jn�����,�j<\��o��] n������dJ�&kS���v�����Q������)�+�����xq�P��u��X]a�I0��I�k����_<�z��^C�P�jk�~�? ������#��(�*�h��Wpn���S��b�U�aZ�:=o8�pE�w��w\7�����l@`zn�N���������nM<���jN��!ws��]kVX�p���l����Cg,��L4���xV�������6[����M~Z�h��,��E�D�a ��<�rzP�j�	��\|��}���H�p�s���[%��W�;E6D:�L�jU���~�\o.c����
NFj)������������f�,hvw�~]�=��	`�_��^������m��a!� _iu?��;�(��k���y�?�y��Q�h������~�wur���`D�9a���1Eh@���a�]�}��V]=����`��)���<������J\�����]Wh~�v��	�xAb�J�^1�X���\����O�Sn-t�_e$8�P���PI�<�}�XO����+�Bl2Z���Q���_>�T����J�u��Q���vK�
��}����������g{���(FH��6��\^�h��n�sR4�%Yv1	L_+���;�]�=L�C;��0�����G�^�s�]�Y6FI`Le�����JAs}nQ���=[��N�����OY6`�_���Fl8%b[��<u���V�8H�p]�����{U�w8����YT��M�N�P�����E�{�o��r��W8^C�I�J����:��L���^��<�1��������>3$��%z���K�'�����lR8\h���
����/���������_�a���u�����/�;���������������*��N`B��\�-z�.���
'.
���Z�}��8��W-��'�,�����H�]��
���!����y���-���_��u-I@=�g����H��I�2��{����m���#t���"4f��o�.sxW	?ia��J`�5i��������Ri��.Ae����h��7�	}|�
Y�z�>}�T?�����hyaZ��|����.��������}U�yAr�$��\�f���������,[]�J�D�?�sLq/������o�g\TV� =�q�\9�!����Z'�E�$Nh_������e4�������l�������S�3A�-n�"��N�J�#�*�$��%��O�}�Y���@N�c�(�a(@�^x����2M�j��]������������{D"����B�,���1�ji���X����_�_]Z@���EZ�����(��kyQ)W��y@*S��$��H�y!�.AM�C�p����vj�	�6� ��^�i�~��i}TM��A������T4b�o��jo���&�������9�#W�������$���l���N���^6{�����z�Ha���;}�y��,}-����g����Iz�c�vKf�b=g���X����Kt������D�+I���"���'Mh��jEsM�U*�"F0$,��V$�Gu�$�G)�!��6g`��O�"��q������K��8����������
*Hl�������ON��~��X���	��@�/�-��Q\���uz�4w�~	 �8�0�\���
�W���W���m��B	`�'�1f�<��ieE�6��O+K$z�������%��~g������urR�B6����F��@Q�>'���a������pt�AO��/���/�m� �q;\��!�q+�$���e�.������������%jV�%c7i�2�Wz����q�z���}���~E6�F3�,������I���GW�O
�������b}�HG��Q����7�>����	��fnDt�9;=E�������G�!0��D\�u�r���v�Z�������M�������`a�|5�J��]w�����E5�v��L������<2�/�~Ha.HL�	F�\F#i������b-�����~_�&�I��A�O���/zR���+�{$^�"������~M�nC�B~Ty�yEe��D!g
�@mK�_3���]EB�x��:�m���]����=P��j�Y��0g)�	~Q�[�����J�\^��O�H1Tv�x�u9d
4=E��a)Y���6/4w8��zJ��Y�>�$0 �
>@6�C�IsV��mjfd?u��F���I�5�I��x�h�_z�t�O�Jb�!��6��(Iw������t�]+H=3��I��x�PvJ����IJ�o/�����'L���"�}
��v�����J�Z-����Mu�EC�����@�����:��'U��#J((�� oJ�>��ZD�v�D)2�Kg��@Z�����$���<��'����]]�[b�2�A�����	m���)���������!��Kj/������E%��bw���-d�h���Uq��!B�
�K��v�G�Th���z�4��4�q'����2�b>4-8,&�F�T�����,2�{1����+t�9�L�a����q����MS!�^z���E���+7?��"�,j(�	N��*cH�T	�~;�3��Hw�*�9�".�9F8!_#��[�Q�5��_M1�uY�U9����c�O������y���������m�t���3oe��m�����[5%�aM��dfj�F���#C)���I��w�������JX�X�
wq�1���al{L��.����\L=���6���O�������t����0iS���<jb���kx^K�6��#���&��;��`���;�F��h^����3���-�X�}���*><�qh��<�_a������a�o��X��3���"`���M{�%��3)��:�lwb��t������|���|U$�`F��u�|��5�-�����H��!mb>IN�a�e��_��h�Wm�OZep���`�uX/��XA������/��v��d8�Qo��a:q��-���z>C�����f;�j;��k����4�=tUt�}�5]�UVN]Z*R��d�]��1PW~�CT�%�-X�3���\�}	��.��b�N�^j��Y�<�/j��e:��^h��umA-��*���'vH���&��L�K�m;E!m��K��d�l���;����6e����-J�p:���\t�r�����:���w"��'�'����m �`j��o�M��9�p�t0�p|����:�^�'�}0r1_���p��XC	����Xk��|�E(���)�9�[�4u�o���9Iu��.�H�-���C��OQ>�u?���1_�������"��t'�$�>AT�����.����������
@����:�g���^��$�����v��8�<W����n?�|�{^��C�{r{s��?zH���<���jqWQ�1�f�`y�iP�7�tRVi�r��������tN�����9�*��W�9r���(M�:��>������~�L��W$X�31�5y-��}���o��{6�
��0���mA�
[h������e����S��g���C}����Qz�]�wI�;wiost���o��UZ�zg9N�M��28��oL@jshD����$9�I�CMA@�]mm&~�����u`��@�*R�i��	��
�)��������-(~�� ��1;?��9m�`z)�������e�v��_�9:�T�"��I����4?-n��gD	��yNV�����a4��0l0�C�
)�N��.�xo��u���yz�DA������h�loc�4��E�S!��@� �H����0�W�>�ccjt�������Q�]�mn8�����c@�t1� <�\�	|�����d:s
����9Q��PS`�tm��f�c��%Wyi������U�=Dy|���P��}�t};�Y[�������=�0IE����+��K�����1�$o/�������g�;"�R��C��XL~�9�?k��T����nW�]���5�_p�
2�a���#~�����v�������U:-���1��>Z����0�����m}�5#��g�Ekv���%��.4o:�7�S�M8�~�j��k�f^���W[T������l�lrC�;������d��T���.����%�pD����<g��s;A���v�L4��	n�y���� Cq����]ib>"���������Cq-����;�-Y%��8B��
��3dR�\n�}�Z2�����#
���Q�C����6X��v�����v#��9MQ��&/E_��T���O���&����0�5�D��0���,�jS����y4�
��zO����l�^���Y��OmHFP���u��	��Iq�����h�pT3�;�@��rI�'H����i��hWF�����g������w�f����j�9���%t��\J�tW�(���md��4o_
�yid�Y���2��0�
��X�U�^�W�
���`+��e����I����s��(\[n&��P6�f������]�Q������1�^����S�W�*�j�j#�	^qu�����|Rq_Y��f�
�^��4�k��V�t����H(���+S���I��&���(:�Sgw��<�9�E�l~m�rT+���L�w�����d4m�*��l�T�����G)\�$�+QOG��w
o����s4|��D����$��-�T���K�QR�H���S4?������R<8���U����!�
�s��4��G(k���k9�8��%���E-�1���������������P���a�`j��5��^	mm����������-�3x:c��5[MQ��`Bw�Y>���g��*A%I���N��U���:���x>����8���ed�n�>x:0L���2�Y�847#:6p�y���p��`,{`��J�Ls�~P��S�b�kqq)�E'�Qv�q��F:]�������/s��X��>�5�U�4��G��(��y����Q��?������s:B�F�	��;�EK�b�$9����8hc�������>�l�\�:d�M�@��d�x��A3S���wW������OQu�]�R�I��g5�KWV�}-��_����`�}$r�^]��������
�`�Z�\�2��������9s�X��1�����\���m*!��;	p%�q��4�x�����K�r�������D%��j�n�t6�sP>$ ,�Y
t`s}bJ����k�dF������F�I�c����y(	��<'�����+pa����IrI_����.!�����4Q��oZ*�,�=Lwn
��9#���O��,o�0W��<F�(�h7Y����l#(�_��FS���j�����_�Z@l>����W�j�d�Bs�B����c��O�E����-��U�c�)2K�w"���E�*��q��r;!�g�b�#����� 2�{�_������F��h�F���WE�h<*�[������2)�����������sU�pT����p���^f�T��YO����4/;��������}+j��i��i���Dz��������B2�������(O'�����
���+�A���;&�t���m��h�n=G��p;�����[dJj�m��X�c���M���x�����sU&�5?�t�z�������G�������H�d�y�����x([�~��+��h2V���]�o�����J�7�C���CB�����p1�s<z�
����l�l�8��$1E�3����.si�����Wa~2y���r��j�Av�+�-����o;N��Q+�G�c��u�]�r��OQe��2et� %/����c��n�&��O/z�8�GP>Z\�l������ve�(��t��;A�W80O:&����F����S
�	������t�f4)��o�����p\�3w��dA�UA�u$3�8� ��K���/e6�A���F��n��\Z1�����}I������
��5����wo����&�����f��l��N��	��nL�lL������1�������#<��G+}��5�,����Q���WZ97�p����Ab�n<�����W->7%�g����4���rJ���mw����Hu�[l���#Za�������u������D�m�A-�m��z.�-rNr��IfEs��~+����<��pX����g�����J��I|k���h(Q��=��Ux,U��(H�5�����W\�����3/�\	��I�4�O�v~���5_z�1���Kl�k?�0��[���7-��n�ms�l��K0���1�Z4����d��	^{Y/�4Ek���Bt���Vtar���~)������@�F�l�����B������Pp����U����K��`l������@��5�k,C���_��H[�AvlV������J;m�������M�u�u�p��r\C{�X"!w
6��>��g���e���@-���1�p{��S+RVj3�4*����!�?��Po����Q�������2��<�	�W���H�Mkc� ����<��Q�d�����M������!nBO�=Z��x��	+��B��������*UG����Z�s��c[�]���!\;f��K��Ug�S�{��/�-v�������}��h�������/O1��s,�oSL�jO��WZ�"��L����#L>��~3S����)�t�+��s������&���jg]�
+r�&���K�w�I�>��V.p!Z�
���+��u���T�l5/����2����cN���]����3�'��k�@��"`d�F�%�iP�����8�A�U�(�yvI�����qT��i�Es�N�\�����JL�,�1&|�����������#������n�\�g����G��\��ZF
�-s_�0�kc��D
[��03'1�J\�x�+"}�>�����p}U�
��W���������Y������pwxx������%�j^����-�/�*(.����S�H��S�)Sp	����
>ltmM��t�c����;�cQ�?��N@��-����&?|M��/�1�xC�I�s"f��u���FR�q� (&Y�E��)K�,*�Z�$�+V�������_������Ki��Q���T\�f����|�pf��V64�(������������ZWd��OM(��S9R�m��'�9���X��J��U����!	�3��Zy����`5�J�e�0��P�/�T��n��1d�Q��P�&4��B���"q�'�o�%�[��I��(����"��		�1��85Vc�~W��t��W��*��<T�I�k�q��Qv�U�����������<��o���Ir���}�O��'�9jg2�z�-�v����dO���	H��T���dU��,���I��y9��G���k^@`]��;����{�Xy]B���L<Qx����"-H�+c}?�����Yz.�K0��q�V����G��]nc�Gd��������q�����C����h!~H�x�	�~}����D14A���#������8&v�Oi���]���5z��v�r�E�2cc���R$�p��}���I���wa�j���3��d�15��`m��
�h��f����������l�e�d"|��Wi[*��"2[;
�&�W�|^���l���!���9��CK��p:%?Zbg��|�H�nQ�
�M��r����;X�f��Q~v4l/�Z��L�����[t9�E���P�v1�����k�r�8��� ��Qf/��Q2�[Qa�~�����t":�c�1}��M}J��������53���������������+Gr�u��A���$&7K�%{>]���DBPaT�o�<�(d]ilz��f�����I�Xo�r����pH+�{����[N�������|!q,e?X���#��a�w���(����%@�+m���{�e�F7��<�n��*G��NFY��hl�V�t���QeT��3��_C� �y�V��`�~T�d������h���B6F=���v{���r<���)��X`��GB�XT�$�>������}���]���D�
�����b�&��e:�5�x��.���TR��]Q���D�0���~85JXS�o_"U�||H�X���sh`JC��l
�|��*���Q�1�1�@�M������20\����{��n�3nai#0��:`��uE������|�������P[�:z���C+�-��8��t���J�}��d����]������- qA��:��w��B����q�rY��v�3��+�(���$HTo�[/�����3�q�����1�A�>��U��D������-hX�M��o�QJK\��a�H�=�!�5-��4����=u����i%�����9�B�r{�^E/��?�2QSV��bE���"��qll�����'&�Lqt��0t	��� ]��_��D�%��W0�x-H�p���[�yyY��T����M�6E@�����ps]��W�i�����4����d[�R��s�kD����k�$)m��]�;`��O�Ts
�����!�;�.� rk�)"�R.u
9\��P��-I	v���������~�UD�3��0�'������{t���6d���I���������8�=���1�$)k-�F9��?��g�Z�,�����x
�(�QIT�Y�{��y�pZ%&��
f
����Y�N��:A����/t�}@���^��'khm�i0!���/���J^������RR��I6������%SlT`@�.��^�
[%�I�u���Q>fL��C�� H���<���!��*�6<�Mz4�m��P��j;7�����s&��n�1X��:�[�"�&�Y�},R���50Q���M��R�6�[��-����	����g��v�,-��n0��,vQ-��'r+��x����q�i�z��W�h��Z(������XJ��}����������c�NJ��1}~\����`GM��x���uA��*CF�7e��"Q�������o}��]�Q��o)."�
Ly����jf���5Kh��k�Tx�Z�L���a���nHb�3��-G��y+�4O���
;D+,�����.������L�Y���L���^A�e�X���j�S/�(TZ/��E��>K�X}�p���n5o���X�5��z�K��^�g��}�\���9S	�>�b����Ut^g�����7
M�&�EY@�������ko[�4 �fm�
�l��1�i��gJ?iD\�,c�B���w3M������������/?���/cQ&����2|��E�IN��,������?�����u�����{I8�J�F���q��H?2���ZZ�O<UW|��f[�e�iC*h��u��
�Ua*
��)����
?��b�]".>o+C\������<�gq��	K}4(�/��IZ@� 0=��8�T?�=%��B�(�,�w�f_�b�J(Le��A��)��e��t��9�����cc
���|�?�g�7'*,j4� +�nKU��`���Q����F+O���{�t��IR�.h��W����=��M����FF�����~�Y��$��	E���@s%t���2�����{��\O��5��� �:[y:-viSk�U�'���	f�����;�{DH���U��d����c����~��l���\����E�e>[��M�H�T�M5���������$�UjR3ZqVsa�h3�|3m�j�4{��6�q8����n!Xc("�6����8j{�����d�8�E9��"�K����x�X��E������,�@B^y�\)��AF�*�'��w����:[��e����7zS��8m�����i��Y���`�d*��"��#ywU���g�������2��x4���x���8%��(�kS�M9�A���!��>��-�
[��M����?iZ=���T�G;�g�V)]��.-�&�o�G�JZFqc2�Q�
�����LU�����eC���
���W���y{��<�X���\D8�Y>��x�4���s:�V��b��(K�'�m�i�������{ 5��3`��1���u�S�M��4J#Y���\z�:@M!�U��(�>�h���t�cJ����GGt_DO�<��A��@��+�5�Kw�:�D��o� ��<�!=��d��a��~�`�%y��d���8�c�:;�*�*#<�y�^�����}���8�s��5�)	��R(���[m�P�����.���B�
"17�U+?5n�Bt���]�8�5+�y]���.`HKJ:���O�
;�#����IA�E��\_���WA�]b*�;	����U?F���j1��k��������a;Q*1r%�����Fa��!�D�6��(0��!}���<�b��Il��PY �-����4���@pC��8�&�Q��ge$�����w1�J�[yj	IyH�A������N�=�`Y��\���Iw�F���.j��$������ZTBUs��I�{�sV�P�NA���a�nF�V������yO�-]�R�iq��5'�Z)VO���>D
�B�T��%/��.T�3m��q���2�f�7E����d�w0U��Bgybz_^*��<q����4 �Sf��z3J}�o�(����[,�o��H�^�1tj�dD��@����=����Z������F%%���>i�V�~n��=b�85��|�N�d5��������&���cQj�0-����~L����ve~����5eH�B�|��x��E�t�����%}1j���l�
����U�>��phv%��r�f��G�D&9�tv������^�V*=r3TuF��-�~�X��A�@C�6�Bz�E7�xXY�n��f��<�G���.�[,{���pD�:fO��X��W��]l�������5��q�������<O��O�D�������� ���Zz��������{��\�������4��w
���������"���TC��Ro�$�R�r5ZS����!a���_I�	[,e02�����dN%��I��>)4&�1������S��f�:PQ�����C�1*�,!��=<<�h���7�[ ���X�s���R�O������&8����O��Q���
�U��3UolK����!��I�C.���wci���-�m��p9>�4���N�o��,x��{�j����gGi����2sA\��U��a�\�'`��n��H�jC�e6>r�����u�-��`U�]X�/
2d��q2K��kF�RnH�X�GL	�
l/l\�7A�egUM��>�����d�������J��l�c���3�@fH�#��"R�V�N���<Ndjf���,�n�����u���Im�M|w$1���1�,���nCH�:g]�u�@1h��������O��l)I�����j2��M�i����������`L}:b�#�n��@�UD��[{�m������Ng�n��Dt�T[�yS���.|�5)�O3��b(�����99��d,2�.����y5\$�:.9�h�E�����d���\V�~6���Yj=�]�d����`r^��*�/�����n�P���t�����\��RIIHS��%����I�B���c"+���C��p����G5��/��n~�2v������K^��=!)�B
��-�r�*��#��M�Z�PBa=��I����aG4�$�Y�u�S���.���[N�8���@���eS9sK
�zd�
A"GH��@;#T�mc���D�V��40�|�a���q$x���	��<X�I7���X�ar�w��>��)��yN�����g:Y9������RH��Rv����z2�I�qu�Z��F��I���n�z�5��#��DU��LZj�S �yb\TB.w��jX����f�B����Z�,��g����j��af����H��K�r4�OWN�]��+�QZ�����,T����*����/�$}�	T����0�nHIu�x����9����I
T����3���PZ:�V�r�H����{��h��]H��81R�K�Q���gY4&��4y0��[��������Wri}M���9[."�-{�K"��
�4b� �mAU�z|���m��<�h�ZG���^�R|�DyQ��q���BVh����Z�����e�1����f��?������"N8O�����������L���������:{��S�W_�����B����xEo����������$t���p����8@KF�c�L6�f�JYH�%����F��N����skV�o!g�1����qI�G�m��~<o��i��V�
Mg	7j!���TT�M���Bl���aXY��2���+� 7�����XT�E���h��`�	ca�����@!<pd�I�D���Z��d�lLd��,rU�@,;�����o)eH�����a�:�)'���#��
���S���A"
	~�
��Rv������Us��mW����5F��V�����Mw5���W���$MJ�k��F�v
m���0R3�"$xB�	��$����Js,+�b��uP�M�*MFF,�^x����"
TuU����.��nY����aa5����q��|gz��".�8���t5RL��d�x�QXS�M�r��."l����$��������D\5u$m���
��K[c0��r��`�MX��]�8��-u�K2���[Uu�N���P.R.*��u��� *�k��V�9���gWU��r��(�����B���b�K���e���h)���;.p�#j^?V�5�����6�V�_����,C�I��e�@t]*N%�^k$�G�"����k�kG��g������6���Tc
�Z�X��|h���]O������O��+�pU2BVt�NI	^q66�_�j���"1�V�f���0��X��WU��x|��,@������;�Z���5�����,�IyX0���>l�9N%]$c���'����N��P���jb�l��Y$cJY��?�$A;�5��^�����v�w��,]�2�rfj�U���?~x���>;k.q�l��z�|����:��ZV�>��!�f����e.1�9��.�a������zn�����O��D�I�����N��HQRU�t��:o �E�
�W���r%�!�4�������|��*iC�!Wm���C���2j�����t2D��/i���r������9d���8�E���x�0�\�*����N��K�4���4�|���Gzz��<��%�Y���^��R09��h�����R�R�	� H?K�R���K��r[6'��9��m����i�����������Cj�_u.��r8!���d���C������E�T��z�>���L|s�#/�����[�����7����r��>��(���P�:�M!��
��%�}�cY4815����%�C��l\:���<r�y���������E"6��!�^��p��"5�d�+]�=������j��YB�\(��YY|E���,�����K#��Y�����z��=X�=����--�T��}G��@b-�`�N�"t/�!�a�m=���"m�EJm�&Y�j�r�&`��LI]>���k�yX��B�\t��_����$-P�v�H�vm��4�+��
�,)}ZG�"u�
h����&�u����N�-�6���F��po��gE��������
��a#C����J���l���/��1�����l����G�A.��&y����Z�s�p	�B���Qs�,�6��z{L�|�:���{��l�������B�&f8����[��4��v��c��*��%�Fq���R{���T����4���:1m�����H�N�����&��G~X�i��4�m�b��v:{����ib��q~�soo!\�6��m��+/�-�C�?����m����w��4.F�"�zn[~���kC�J7a�zcV�u��.|$B���*[�08�)��3�y����T1�0�'t���v-�d��>�gP��S}�_��)X�B��wZ��8Y��yx�I�S�|��X������?7��h��:�tIH�s �rk�o�a���6�=���Qp���A!OO���?��k������@.j���Vgp�&��2�Wo���O�Q
�:|�HX�F�[��b��7Q3����~$L�H(�OV�(��Zt��z�v	czZfq�Te#�)���H�����G8$w�#�W��p�"6�p4�I����^+<H}� �|\ )��O��z��@�Xw���*�32~��#3�����s��y��0$z���-shNCg����Mp����B��J������Qz��&R���l��;�i\�
Ii�W������3�r+Cc�����IsE-R���;e!���K���x�"�������g.�m4���bU�?�����3���xZ�c��M��\��t�E
�GN+P7i;
c�,�l��D<
U�v���.n�+�5��&�APMs���pF[��/��n������������q������������0B
�;H��ea`iR�j?������&^^�$��Q"#�)=*����<����%+�T�����V����t�XY����&��}���X�uj�_�M�����W7.��5����*x�N
�D�f��%��M��2/QW��I����6I���{�O5T�h�e��� ��Z\#����(��i�B=���Gz���C8�)i���^����d�|G������M�o�P�9�Hc9��mD��������fQ�����m�}f}�s�f�l*�.���h��|���T^
a��(A��������^��"$�&���R*te��6~S8���L�R@�qy�?UT������l(�h��C&_�����ssV�S�[�x6���
~�F��1"l��i�=��Ktf���[�Mz������@��U����KnOO����k�Y�>�|#�	�!9���{�dM(r��c��)�����J�l��z,�!��f�����n��cmm�U�����P��Y��D>��]���Lm��l�X�\�����c��0��9P��m���x���]�y�F��!�L����G�fw� mE�����e��c���}M��Lb���DL��
/_	cy
�
�Qcy����GS-�� ������%����e��C*d=�C*u��/�I�P��U2�����A�e�>�0h�����AO{���@�?�U(���n�:'e��x}���z�V��f�����T�����B��&@��K�@//�Q���#����k3��DRSe�4aZ
�#��..��t/�A>��.<�0��������������V>�-�YN,M�����/����!��E0U�]Dl8WM��u����(L^G��Z�4#�A�*7=�	�:�PV2�z���4���(}I�\������i+�O��B���!�����t)�`����c�t�&t���{=2�[�U:�{w,T�	(�:��4�^{iQ���2Z����H�c����@)��.ON��ka�k�<y]#C��ne�0H��[�K�@�����]c�z\T�9���P��S#7����M���������_jU�l��a�G?Y�s1�U"IqY9hiO�|�������l�n��<$�&��X���o��"�	�:O��S���F�n���cP��-��h�d2O�Aa1���$���� �l��rY��6�
��e�@8^����2���q�@v��������#�=�y���&�������c:���e��w�B��xw�![��U���W@x�B����R4o���R�w���B�	�$���0uV�L`6y++���8MTo���z�����57�O��`-���9�j���t����EHT|�>?�!e�H�F�O�IoI��#�����7��y(,�9�$��ZHb�������'!|��,��M�T"X�v^Gb�HX�R+M���!}]�
�������:@A���eoF�%~�G�J�M�w9�P��u
���Q8 ���37��!��6�c����P��#P�������$)zK�M��,�H��n���xTp7'M�b#��&�n��VmG����q_��XD�7��R���j��Z�7pk��A
����Um���t���i�${�.~��������sh���5�@����J����a�1������
qM��z�?|�~��H��,HG�$��H�L/��!B��S���7�!h�xU�/
C�Y���|yC�h	1���A5�Fj/}A��|p�U�W��db�A�M����>�@��TI.?	�]�����KA�gT��d5���.d�K
q%���7������7���(��<�n.�����}`T���x�����"Q)�+���qp{�=�V2���tV�&��qT�
�?@uG�T3?�8F���}D��M�XR��<7D-�
�����X��'�^��vE]f}�]Z��ih��Vu�A���|D6a@�4�x����hh����JEh4������Zt�����`YmuJRHs�&j�|���w�m�w�s���q(����v���V��$��f:�F�@U�s�!��_�Ek����.A�jMg�5�F0����%��l����e��<g�wl|�
u�����a��$�#���<.�fXT�$�]$��W�e�Xy������q����s�{�#�a��]�_�������w�F`JxW���
�1�SnU�����]iN��� ���Q����QD]�J�9
��O���D�i(���v��.8O(�Z.��>7U�D�U�y	��������(���
 I��-�J�����^��l�o!�g�^T���u|�!�d�������������@�
�x���/���_����������LL+�Y��O����,����?�;+�8hH�^o�QUrE��<;�u�^�F������;���T�=����\�s�t�OS���]����C�b
���^O#OBi�8��Ur%4�o�n���5��'$�`w�H��������[W��q��v}�9Tv�r*��Ce�mp�i���;���[�iA��=�W>�5W>��h+���6>��q�s���R�����:�:�:�z�s�F�{o��9l<��^[�s�E��y
��}��x�s��+�%-�z������NE�s�{|�w.$�$��[&���7�v�9@���iaB2�������Y
�����y���������!���w��a���h<F�Rg����Q��o���quX�2�!��S��E-k�`���sX���:�y��������f�i�xc�~�i�(���Z4ev5^���A�u(�QH��G|�G���`�����6�&TG��=16�|z\�}ZNms��/E��,���
v�m�Eb�����t�<7����(���''[���w������3�vD�V����-S����[���+�E5�B��k�^��R�@(��J
���HuW�Z���X\�<-
P��@T����~~j��p��7������_&��������HAZt3�4�&�w�G^�7eWGc�{�6��5��5��_��S���2 ���s1u�X�$��^�+j6\�8����*NDq�$V2U�L�3�����daHl,�*��_2�C�_�$`F�������p$�Ai��g�9�~S�<���a
�p�y�p�r^&����.\m�����&��?�i���������g�_� k���dU����s���`R=�����;��n�:F���0�`���6;�{�W�����L2���&�k���y�f*p�@�W��z�+���`�����t{����N��1�J��W��W���
����QX�9���#H������w���E����MB�sM�C��q2������jS�5
���eIz�r�������+Z��*%='�����DR`P��-��[&�^T����3R���W�
�JA}X��(�������kq����\��]����M�V�h��i�����k����N;$�0��C��pm7Z���7�n��xxw�fz�N�?����xm����v�}��S|�����������m�^m'�3�GI{�6.V���w�'��-\��8�G���O�~�m����������m�^{|����[��`��-���
m�:���7��o;9���,I��[���m�;���^I;�[o�6��h������@;�{n�:�wf�qp\�Z!�`�l"_��V�G��O?c	n%CY)4aVmOs�a��|���
d:P�����J���Ux�P�E�z�����U����h�jq��J*�I���ZH����H`9Z�h��5��'�x`��Q�����/�v+�C�����N�]���V�b�.��[�m��'K���h\�
Ko1m��B�����'�rZ�
��@L{�@�������;�q��4�N'_oa�a���i�������������vII��~S�aLNSY��'
Gv��zF�n�| ��&o�k��V$:S#�f���9���D"���#�����X��*,Y��i�|l�
w[�jP$dd��?��r �j6���f,�����ZD�KTo��e�F$�\M��Q��6�I�H��b1�E?��KAj�NI���d�����pS#�M��k2�$�q5h���b�����x8y�������#�vH���F�ko�d�:yxn7�z�xxnw�n����m�O|��$�x��m�Zo�>i��B��z�i�HZ�Z��][ ��G�>���m3���h�M��v�$��wzZ'��A�[O{��n��-H����N�V�h"���h|P�C�
3f4���[��v���H���� �������S&Ym#�s���|^�.��[��X{��v���4�No_��y�-���v�a����~���:?����f�����W>����	����*����&7�V�/kAbN��$�������EA���H4��.��H(��*#	7�x��
[�`��P�c=��B�u*!1��� $��u1��ts������A$U'�a�(���8���G��h��cN�sc��\�y)?_~}��u�f\��/5`2�&=�d�H�G��9�����:5�$/G�+$�>2	����(��
������y����o0��!�����<��r�������������44
J���y�9�2[��y_�������s�RB[o��
�FW
�6?v!/+�!y�������X�K#!�����������5lDcc� ����]I�SO�8��b�$��dn)�M(��
mQ�����n�3�z���0-b��k�+��|�hy_`)~�!�e��3Q���}��o����31�9:Sm��3�y��������u�;
E�I��t;c��C��O	?����"-������%��t��p�mI������G�����������%��uxw��s.���8�`Ac��H�mL:7o�.f�6��`Rw,2
�aj$
sD���,y�|�+�'P�k2T�2���0����V��{>�O5�������)�x�i���r������][p�	wi�g�?�C�
K��"I�=2����Y$�4�"?$q�H��F�����D9y�8��k�x�i�@H;W��,�_��*&n~���������a��]�c�y�7AH{h�h'�>��
:�Gi������{�9�����R!�������F���E���*��ld�@��7H����C��R�<����j�t�'R,?|I�+���������>6�$�:C���H��C��X�����Yc�"��a4���k��G]7��>�#��I���5��H)2�y�eo��*��a�|sy�.�}>��)c3o�����h ��=$U�FQ�����E���
�'�d:���vI���"��h�`�3K���x�F������r���`��&��y�)���m��nw���m`�������G�XE{��`?�&�6��4"mPEM��>����o�d�=�HwO|}��v�v#�s��?��oB�fs�H��W"�����-+�S�3��&�)<��0L\�_[�3������.��g��)��e����� �kH����#I�*�l$`��u
UprFV*��U�[&=����"��,4��{�^o��:I��o��N���M��-��4�����������-4��kf��wL @�xQl*#E��8�=�?��[�rS@�G+$��Z]�=�����5��Y'I�/�C�n���'����(D��`��k.O��������zQ�������QK��	M_�-�D��B�_��
d,����F��8t��` �Ab�X�v��I{ht�f��P�1��X�
��E����e��iKy�ic_��<(%�rok��i������4yA�w�p��38��S�n�f�#�C��zFJK
��b��	0��J+Q����M3��d~�wcz(���'Ba<{)��0��,����I�BV�m��6��h��#����@Z��&i{����mWHE��v�bK�E�����Y��w�<�y��6�����&�~�V��q�6"�������e���Y�Z
�y�C���bF����-�46���]�J��G6�7����4E��	8�����`�|
������8��\��8*��R\C��%���1���L�,�4T�}��sC��"Y�:$OM���w���Gf-JB������w$���K��B^�6��`������k���..o}1o�����'xV����LJ*���*�T?���F���\���������)'�<h=�������s�,���H�s���DE��
}��q&�J�>���VuY}z.�8��z�I�b�9�,�fc�\�m�D�(���&��J6v�����*�`��OI�i�I��D�F�3H�%	��M����Q�E2�R�&�Zs�7��7h�zc��_���"�g��Prs���0�b�����5���	Mu:#7���X]�������c��.��z���b*qnO��!� ��t���myC� �-@M�|����V]
J�_z�5���9X����)�<�+i�W&�����T�Y�$�L���n�V�~{��i��E��*�o��j�}����mlVGo��1�Bw�������U7�@����3��cy�IwL���>���(xG�nf����G�,��Uv-|�Fg�V[��0��VA�B|Zjb7�hcs�/}Y�����q��[��h�C��1F�����0Q}*�@����0p}�����3c���������I+��z�o���u%��!�am�1/���,J!Q�c�~H[w�����l�0���F��KP�^;��u�ju�OKv�6q���_�H�[b]ed����`a�@yP�� �1Q��hb������Z�Q���_I6���R��� )��,��<`��}��{3.����u�[E�]E��+��G%�~��X��hH�������di�c#���E�4��Q�$��+�VM,M������h0�@�R-���UO&�o���H	3��c���:��4 ��k�$)uu�%�n�F�������`������7$~�\C
�����A������Z4MW��5�2��8�\{ZuS��Ye��5�~P,�s.���&"�'&D:H>"9��&�`i}0u����2��R����S�����4�\�2���d�EDz=��tz$=���s2���=�����i����j�(3��P�f��S�a�@�����XRt�C���vI����@
^��r���%T
�1$��M������F5Z���l@W�>M�8�$����GM�����H���������!y]Tg^�oY����XW�Cv��^����zxa_I��`�Ge�u�cK:��~�v��+���m�2k^�l�/�u
z�$7�y��F�%0>���I��7[-T8�o��EZ��(#��������":��y���_,Q�o
���=7H��:�I
5����nYZ����Y��j�=@��_2]�E\W���?.2�f��4]����>��9�7��j{�}��_���U�ui�@����h��Gm�U��������zH�
����[�"+L~��S�����������v>i���������w���i��|HRTu������~�$B��EP �O��@�gW��z7g�v|cL�LJ�!R�?���"-h�Um�$�%����*C+%/E!�V�#f����/��[�G������,@e�������d$o�S��V.���8#?B���E�"�+�K������z��Tb���yA]��2�~P,"M~���L%���	�Z$j����X?��@�H�-!�^�w/ux�N_g�F/�?1L!�i��Jy���4J$�@��S�Q~�9�f�B<���W�CS-�8�����|�N$s� py���`���?����=zGZ���6�1�9;"���]����L�*��}@��	]���#%}�8M��GHY0!XC���p�!�5����}����FtzYC��[a��W�M r>�6<n5�f���+D�f����-�6����6Y�Z�v�p&O�7�(%er���A�o�����7��\ar���Z�fLr)$�^X�^	}tSHw���z,L�Y�c2
�1���[7�X�Gz��vEt��YL�q������,m( �@fS�U����`��}c#�o� [�Kl�Q�3(�!�`��E������)k���j}�{$t��pn�$�@/���[�E�I{
��N��AmX���Qs�6kN��u���ER�(��S���O�[@UTO���4Qy1�q(��-$�������T��f�zG�v�6���Ke��,mQ_m[.+q�����X�N�*����:�iDg���F��9�%��k�=�f
Zg�C�6;�}p����cqN���`YD��:�����4R��K� ��KqnN�L:)�W����`�+
����r��N%�k ��b�t@����Y*lP~��#������^�W2�����x\���pU\���l['�\�P����1�9��:��?7�_bQ��8��I����N�(���SMz����H����^�R�(-�w�Mm��5����!d%AA�H������pp������N!
�D�6�������E�k��Z��$'W%�	�cP�S�����s�OTz�7�����v2��!xh0�. ����(!70U��
��:Q ��E?�i/��o��Ae.����i�^�(��Er�S��iV�)*j9Tx�z~���w�8��x�����+�N��qZ������{� ��H�C�Y9�T�H��g�_��Y�O?3��
$�����G�Qsy0$,�������V�SS������j�yNn���W�:��Qv�8�`��P_��?Y�����tn
�(7A�|���R>����.l���b���XLy�x.�=�V�TnP�~�T�q���/�}�J�{��n�&�p�'1#���Y���DC���k���i�I�'��2��]@����I��)/e�q����������|,i�i!j3N���s
�H&��j6�)�$���z���RV���u���b�V����Q$��?Q�
��|6]��$�aG,@U~�*�m�]F� �����`$���E�F��"p���%�� !J������%4_+�M?��/��� A�����Yc8(5!GB���K
+��Z�
������o�_�](�������\@jR���-��������i5n�m�	JExzq��$h�v�D9D��V1��
�!����}����4��RU�R��6��US/�})�$OK����U�m��.��kom���V��-^�G�u
�8����3�
���%��2��nP]�C�w�<���"?�y]�w���RPJwH�G`��,^���Z�[�0�O,�x��.�����<�Y��`���k������h�����^�[|<��%�4����P�de��P�5������~W����4�i���0��Qj��p�
�2�rB���Ah�N"�W��Mc�aXZ&��tT:`xZbY:=*��f
kq��6�ph1�?XH+`*�-�=�3��:L@�2m�H�$L��~��Js
M�J��!�s�CuV$&�@�idv#�SJS�Q���0��D�#��h�����HuV�����`�"�$�����cV�=\K����Cdr_�L�q��^�m,O-�8��p����y��1$}���O���2�2*�+�����(�"q:xW�^/���t}}�T�������.N���i{��D�W�(K�*�&�cm��)k
8"qW���S��4�{bL�V���5���R��]`�.��>��VP�2� i��X�k#r�!	!�c����r0�����d��������j�$�T�/l����g!^u��1"VxdY����x`���y�udM���Io@�����#�F�Q&l���vZ/�zw)	4'��������ej��:a3���tj8��n�I��a�<�w��$���H���L��B���rt�Y��J��[�U��;=�`�F�U���=]<<�}P�Z�����E���?�}v�H�,���|�:?��ABCVa��s!2mF�w�X�	�x��$���.�:uq�)���3�,{���a8����?�����M�d�2;����������J�B�t{��
�X���g?�*���z0����B��P}��k����,
��z|UK��'���������Tr3�������}���L��A#�R������|f��F�1K�Q�-���R4��463�sS/G�f���4�x�����!=<�����0���P�P����O���*\������������/�7��lC�����a�8�~�?:a�L�1��_�_���[�G�+���nN��kST�4��;���]P�X
?������ThF�Ua���:�TN���53�]+�n���l���O��}Y��7(x���,��y�����E���%���?��0�<R�\k��:����,�����2�����I8��?��wv������B�������YTYv�y���;"!��5X�J��bIQZ���������B�e��a��V�	n����H�h9D����U�`R��,Uc������y=��9~��N�Y�N-�G�^M4bn6��1F�5'T��6����-��C�%�jux|��F��3Vhs$"c�������	�e������}��v\S�i�<8���LCN�
"I�PH����P��G���+�c2$�T��H������LuD����@�=��,Mv-`M�^�����(�d6���6'�������^�G�@S���h���XD:�]F|�H�xP�����=�uQ�$�m�G����Z�������I4m���ai����F>�b6
tN��zjWg�����4j�vH$��=�&9fv�#�P�Y��I��j��I��d0��
�t�.��������� ~3R�H�S v���<�f>K���+K@��umr�3u��&=�nx=�Q�z\�D��h!a}�]�|�2O��h������
��C+�X��T���mG�g�l��Ynp��A����6.ff��28����M����!,����	���Xnq'�����`Q�^�����{Q+�)<p�F��� G�� ��0yQ�H.	c���D�V�w��^����~��_��:����.��y�a%� H��c#MqxF��z������T��Fu��4��4��pFZ�h��)F	=�����{k���n�{N��g�8&����?(_�A���%�VD����qT�
84[:G-R���T;
�A�3�Z�5�:+��l�+O�D-a�7���a�
z�u(�m/:xN����
x�h���H���-�:i�:d���9������k�=6x�5m�Y�#��)�(S����d��@U&?�K~tN��53��k�DQv��deM�
aWUN2��@�z�M/q�@c�����T�9����J�e6����JC��� �������>����%�	�O���L�|I�a�:��dv�(R���C`^��N�n���FIw3#Y^}�BJ������%SQO:��^���=��|���Dhb����[P@a�@�
S�Ft��njkt�m=3g��Ir��j=pB��1i���yh�����^K~�=kL|K��-@���m�YF{��]7�1��>B~7yZc�T�g��c������������Y�T2������o�8`|�p�U�4��Z�$V�I�hq�8m>FLFmK:r�~��J��@��A[A2j��L_���G*����"I��od���_$��H�.�A�)���P7����'���2�!�f�Jk4����0gbI:�������� ��TS$���9fg	�:�w�DW�IC����dk���D��3�r+<Q}T�A�(���o�Q�r��9P���iL~����.�(������P�Vi�s*�#���s6;"Qm��R�+p���y?]���wa��q�4��w�q�4�J����u�������y����b����T�_�8���,���
)��"�c2MT_N�
B4�ubAU_OM�|���@��nY�v��i������i��%�=7,��\�6��=���T�F��>��9<,��^�>��-M0�@S��;U;lY����Te�������{�R�!G�E�����{(��>��@+q{����L�e��T���u�_���.K������3��������w@,8���v�gDPg!���R��:]O�#��"�8m[�CX������r��_)������4k_����`<E��������~ Dm�3Kr
P}S�X;�r�r�������?�0o7�C��}(��nk!o�����E�5����u�(������Q�������<\�\����,u(����[�$�S	S�o	��l�R��!���V��i�BB'Zh���^��.Z��E�&@���\��N��r����#���B|�h�JP�c��L���N��(*�h�I����$��@e�e�)�������hf{-�e�.M��R�(�,��
���T��i�j�R>��n$�+��F.5��0�>$2��*�e��/(Y��A��{���"��H�3-���%��r��.0�3��Q3]w����V�zW��W	�T�&��	^���f�h\�-P+���n&C��Y�aB6/�i�m��Pv��IO*���}4d4���c�e����>|S}���'�0	zQE�n��T1T�(�Dz\?T�i���^1�h�{W�ZDQ����>�3"})����RK��.~4����a��X� }�V:�����X�/&���5��I+!�[��L���������[}kN[�JVJ�����	�U��5-���o�=Q��BU`5����O���M�j!NE������r����?�t����N=���ITP���g�����X����i��e 5Z�~w09���@,K�f�y�Ye��J����rW=3�[��U��t��mF`�{���(�[��>�O�	��j�.� 
J��h�u"rXR������g�]�Tu�^h��B�kN~�
4��_���>rT��o����u���)z�Sj�>j:y��BE�|`Ti1	��9S�_�l���%��k�����:fW����m �s�0�X��LC������aZ��IG���9
}J��$g�T�0��k��OJo���h�:���B�7�3���)����A��������D�45)-,J���%	n�>972�m��A���.��\B���
z�V��Q����>r�p^ge����s�A�N�6k����fG��H��������QC?Y���OkS����K���+B� !��D!�������H
���e��h��"��fY�����R�7O�
���y���R�;��)>��t�L��Z��Y=\�|	�b��a�@P���������������m�������{���;K�t^g��������3��g��+�s��p*�&{�'��
���A���q��{g[N����yk=�\X/�-��>4����W���VX��N����\�[�	%=�Z4�5��"��T��YE�d"(�g!��6�����7�v����t�[���0!�����w���U���Y���Gg���[0��DL�"~'�S
g%.�0~}��+]��fC:L��J��*��!
R�'�PG`_l�<l��ZC�vJK�a�VNjL�@���d�j+�����mB\s����K
k���$��
T��@�����x�{��g������^[C�6P�d6!!��M-����T�������T���������3^��%)T������}���L��O=�y���QY$n^�G��W�Hl}�6����T�WW����9���w����P
D�����Kk�<Q�\jb�9um��-kJk@n�Y�$����4������Y�&�;��,�h$��6w��60���O��@�z������-oq������_~\C�)[�4p��-,��2�j��b�i��}�����B"�������e��%��l��P�_ 2�������g�����}p��������?"���g�s�
�������i/�'
����/��@�I���Q���~���~�/��X��Y���=��������4
J�[y��,c�b�#��h����VaPZS`�������my��W���_�@����Jr*�Y�����X�|a����~V;9��J���Y���r(�����'uYJ[��`�Ls�c�Q_�|�TG[v�y#k��F@4'" ��������,i���.��1������~�3u�����.�8��3�/?���/#������������S(��h�_� ��X��W}�_���V"1lM����?���g{��3����22��#Ia���C�i�:l����-��d���%5�emk�wbI�)�%+�*_EM�,%D��J��~kQ�2�V�����IA�H��}3�2?��Gc>��p�F����������MIas�k�������k���[�n�lVHe�� �L�w%�L��uq�[��4�y@vr�
~D�|��!M8�(�i�
�P�����n��1��}��v���v���^i6�m�����5�������;=$aH�EH���C���v���B��2�y��NG�_}�o���;�"�#�LKV�d�h���o!�l��a�q�$	�w�W����<������;�4Ar��p��[���^�<��@��z%�����^�[�|rK�G�����o�����Il�a0��Jx|�u��N���W��+-���K�?�<�kV��^�m��-;�_�68x<e��x�K���W����;�6�i9H�?�\��o!�h��h��?Kh>��f��������t������;�{}n���vs����Sf��?�4����=����a��N�wz8z�S�ZI������wz�}~Y��
���N6=r-�yf}�j����S���C��z�!m���=f�$�����y�6�V�q�u��|Z�>3)�v�9z���^���W����\�+���>�S���@��������i�KCZ�sG�^O�����u	�F~���[C�_}���
c�~�u'���7��e��O�2�j�F+�6R���B"�vo�����^i���E^WH���s�<�JI���y�����c���8�G�7>���g�Y�|�!��V�����+�'������S�y���s��>O���u��~��%-��e��W��/Kx����OoW���p�1��V���49�k_Vr��-H���I�����M���	h����\!�c���y� ���&v^��c�%���S�vI���?_h��,I���<z�@���	�����|>�d��\H�>���c����|��d���ON^i^w��{�{O+�u5@��z%���=�<����WZ<���/z,iG��v�����r�w���N�B��7�zm4���g����=�o��s�]{��H������������@�h���'���c�]�����1���Nc�@����i��>m�S���BB�����<�4%�!�c-Ar������-��QF;��z�����^"�����7�f�>�����`��W�4�c� ���S����H����+i[�&���������y]!b��w�����v+�����m���	��W7(i�����a�;x�j���w�?ME�v�J��_]����jW����N����p�E�����u����!����]����H�l������vE���4�$m���\��[�{�~�ym�_<D�B��g�S;��Ok�KA�Y�������'y��������(I�F	d��t�$b�V��3:7
�R�R�;����>D�[��$):����`
������b�9��=�j�wh*r����9�D� ��J[��C���v��>wZ�0_����� /��-c�1S�|��CX�E��Hq����#�Mo�������@����	���U{��j,+y,b��*�y%���~^�����X��Ia�Lvk�w5u����	 ���9�+,;/e���r[��Q���s-���Q�Po3J��\7T���<�����.�-��`��x������x<����������Hw�K��3Mz����f�Zd���i{��Ow��!��N�7v������(w�<��������8D��#eh����~�������,���;�p��3�E��F�8��W���Z��!!o�(��*V���m��~�����������������[��v�~������.3��Q�X�2�c��Vv5��5���d�6���zB
6�����YZto�|z�u�6��]&
p'��m�Gk��4��W���<tH
4�M+�X����yn��E����F>����MZ#vGi�|9�]b�2:��[�Q-7:�!`��z�����ZV���H�g���"�@�Xc��f���i���������������������M��h�F��i�����<L��K�����H
U%S`�;�{��~X4�:��J�����y^�����1�de�Jp4��2�&=m������ZX-8��*mcUE�x�����:������[��m]4(��fF�h{[�G�L��h��Q4n3
1��XY����`S�B��`c�w0���V����|b��t@P4a������E[�\!|o�"h��}����y�9���W�9��������!��;A���6�v����%������k;�m�-X{����8���E���W�4KlG�U:�h[[�=�v�U��h�-�����,�����"��[����m"�6��V���Mb������'-���J�M�EK<��+�mc���<z���������+_�v����`h���bG�xfm7���w�]y�
n����k�����&i�v$I�Y;(`�H�����O������p4��m�V���[���&�x���>���.�z|���GE��������1V#i�I(���#��E>��)�xJ�M�G�����G�h�,����D�<�|�1N���0�&lS@0�x��;����%�$��1����6=Y��x�l�����vXm�L�n���9��������h[g
���x����6+C;�<����1�/i���I����x����c����S*1�0:��{%�V������(_��6i/@K�����Zi�!�U��h;��9�������oa'=��A��;��;��%���eyP��M�
I�x���h����SE��2�6�N	A�E��+��F��+k�v�)�ch��m�����L���<�08v"<�\h�du<nNa`�}�h�Y(�a���1i�	%���)�[5��h�(��u�y���=�l��v<��Am���J!h�������k�
!��Y���P4�\"�l�M�����?x�������Q����C���B����F-��M�C���k������~��-��-$���m������j�iB:�+[&C�p�,=m+����r�+�*Q?�����}z���4���;�&���X���aMV�V����_���X�4L��r��ZDOs
+L�6��^��8Nt����S��*��kk"��J�"fa���i��>��]��Ee�EA��i��7X	EZ����B��aI����B���N���~a%��j�o���V��`u��/�_���b�`���S����fC����5-@���D�P�m��^��h�Pa�-k����U�x�+�Etq��/
.I�W*nP�:{g���7
��������6����V��E���1�0`��n��6L��h�����v}l���S�Q��hY��/-����Li�5]N#�\nU��fECbEe����u��)�F�I����O��O;
3f|('����.�Y
�>��u�[�%DD,���,sueiCZW�7�+O����^��	;0�r����8T&��vr��C�?Z
R^\$���s��3"_g@�����n��,N��5���*����S�l�a��rZ�:�Wm#���7�6��-m�]Cw$����F;��P�F�M���v�=�d��q������p���� Z��@�mN�v
����0��n?,�#�[����O���w�7�����h��Q~K�%�i(O����-$���}1����k���<���Z���������Z5v��E����g��+��u%�9U�s:���0�UyL�wSvu$�R���3%J+���ty,��b�������.y��)�_ED�I_%�G-�BF����"�(�W� ��Wh��Fq��i$A�J>���O�:��"h�#�"n����h��E�VuY}��n$��a6K�������jq���H)�}�wC�3,*�����K��YV�����V�C�!����T�#�����Lb�>�a��@���{k/������v� B$J�
�� ����%x(����b�L���������7�Sw},a"��jB&73�Z��FE�LI�zx�*�[�Y���`��
��q�0m�(�'JZ���1�����2�Ys)_I�Jn��*�A�4]R� �L�LF3���#�E���d�( �c�y���b��r��J�L\�E5*�E����-N���%7�q[��n�;���,���?*EO�����z�$R�5�f!�_o��a�I�G��*�Nj
�;�,�p
�a�������>9����"��^��)���������im�������L��_�����D�{�����Byi
|�ygL�m�����U,���rf��w�xUI����|���~f��P�NX[�s��)���3&o���
���Jn�����M��Fh0��6����*U����F�������&o�L����5e�`��W����j������J�3`\+�O��	wL+?i!O��4�0"Qi^e��B�:&����`�	���sU�Y%-������#�c��x���b���}
����P�x���H��"�w3�����]���j���F#qp���O�������o�V��=BDT�MO{;Xo�{���RI�(\UZC����5DU�"�>�R:���b�<l���U��^��B�+,J�����q`�Og�0$�QP1W6��~��lm��S�f����ILT�,��U8^�����,�2�v3lg$����e�S�".���~4[��6l�&�����ch��h�z(L��|�7E�p�JI��PH�D[[�CKV��_KiC�
-��x��Z�:�(�u�q'���P��D3��)��j8>�B;�|>��q��H���w�(<�x��$�;��x��pm��`�����F��&*��MB[����t��Z|����i|�o����6\HK�r�Zr�x�� 	<�27�f��H����$����/��V�4�~=l%'�����
9�>l�;�4B�������u�E^,�M����0�>���������%i'���
��H4{�4Mnn1�
�K_��a�
��h��Jo5s����t������4E���x`����D��-����v��D�U$��v0I�-ix���{��|�������Xd}�/��3�
k��M�����@���i��0-���R�mF%�U�^^TC��\�UYf#�uHP�ugVe��z,�%Ql2g��LE����%���������~�KP���O��W�/����J���\bD��������!�|�������7�@���U���E��?��A�ju�����M�������o���a�Z;�����?�����\�|�}���xh���k�����=�l�2�$�S��7�����_��G^=�%���q���6<����U��'�]�-S|
��.��t8JJuf!oD�����SV�N�RB��Ry�\x��%�i�"�r�C�^�)T`B��yM��^���"�l��\���n��d�����v�T������R�G�eF�i�N�'+oB�-����/� �`$�??_s����t1��,}9oZk�K>m�u�ER�"=�`�L�t��O���6�]#������V���&P@�����l�2���v���������;���(�;EML�Hc��u�D�%H�-�[-��)Ov��oy�,��:�4�aXmI�i���6��1���������G����=���.��/
�S�xO�5�{Qrc�g����3���0?���a������70�Q7�X���e��[�ZZ���&�5�{������0?�������=��LK����SGn����r�&�e���5*1�
$7��
��(�������h���9gw��R<���P�#���a'��������t�g�����[v%��u�f�|���j��t��wS���j`���,���������*�������R��UoRK�X��������%���f��P/D@���/��+_{����Wum���<Z����2�w1�V����(���2������}���'���"�����aDy�����gk2jb,���b\�	��1�b@�v��>g\	��uqhjc ���'G��������1�o�\�|)�n�Y|fb<N�T��-����W��u������B[�Sj�9`����Nq����V�!���+�#�	���451����M�5�
�
s��"������B����y�dt�x�0�_����UH�H���'jQLn ��Z����t#���`t�cxa������	�j4�:-to{j�G=���D��y����2W��^���l_M���������t_���a���I��
���9�����]�Jx��M��]ltLq����P��J\��t,Z�Y(�r�N�e�u�,�-�r^�����v�����3"��Z^���F��<I���wL0j�a���Wm��1~�l,�2y����d��o�j{��_���Wr$����	��������U��f
�K��� ���|%q��_�n�d��23g�b�-��{��O1Hws{;��E�����,��P�Ri
#i���~�q��[G�c���}.�e�j��_��y)�z-/;������O���	ap
\���I�*{���X'�8?����y��:�L���G��xu|<z"���Q�&����M*{?����$:�PU���wj���q�U8e���p�V�"������d6�Y�N5������c�oz�@�i�1=�q�z}��LN)���)���W�u
�����/_�(Hpb��q��|��k�� �3w���-�I�YuP~�y%���������-��K
��:R�%�l����u��V������������o;��-�����y�KQ��n�mv�:�	>oZV��
Gq��O������]��S!�O�����N��Cb� t>9�Q(�^���]��bU���*A�3d���/������%9���M�b�d��k�YL��p�g�r��-�R���.y�A�T�E�)�wkY��4z`�L���i/�M����D����BW���.��T!�����~K�%���C^��<���u����r�����cn�d>��g1{���%�m_��� �g��Mu�d?�C=2����w���BI#�dh�,��k��������6k�q_wU{�Z��}��)���t�~�-�8y����&��q
�"YB�1L��z�}9g���`jC�$Z����O(,F��{��`�I�;xj,�M���mJ:���S	l;��[���p��'y��g��;�����$���_N��B�\?x��;VI��+2���@���N��6u5�y'�[����J�]���K����P�u!�W��t��*w~��A���.�� NQ�s���y����]vg,*����f�qP�k��W<k�����}����s}S�]
����n���@i	���_�G���^�^������fc�;��/l��W��� >o����e��j��Hm�Q�
#�����9'�E�y���D�X���x�p��!k�%��~M�)esh'�j��q7+�s��
������`�9���RU�����9��P���f�v4!wGT���0G[�#k8�:0%�����"8o(S�������R]�z��$���nN������~�(B��R�:�N��:�����I�����x�J���xW����BW��d������ ;T6Vn@������S'<fX��6lp��FBvK������UiY�7�68��P���\�[����|�[���6D���>�m��:�������_�}��IM�,�w,��&�����,#�t~�L�S�L.3#97.
��"� m	�\�<r��,���t{�%$��e���L#���X��[�������d����U������K�VHL���}��rw�z+v\�aX�L���;�����b<'�GW����0)��]�%2��TV
 ��CN�'���r8�&�!u�����j�>�m'�.��v��><��JU,p<��w�U�?�
���H]�Mv�W H�K�I���^3�n����{�vD����:��7V�zM�Y���8D#��b[��^������H���[�
3��s�nzDN�~�7Bv:�u��n(�I��}����=:����F�b��X��������1;�\��]C\
Yo����X@����`gZ0�(���F�������#-�loO�z�u�'�K�~�c�S��B��w��:���f8����c�IV;�	�3���&`�s4�����������b���u(�Y=3��2��<��4�y1v<���M8-���9L��s8ngl���m$&]��=�������-�_���u*�i�9����{`�z����3��)��������K�����J,rv,v������B��#�=2/t�DE�j��F��jq6��
8�c_B���l������i�Zn
V�M�:�U��[)zY��O���I���T�}i�wJ��
�$��������}q�m�'@���m���c��n�
����C�&��������x&S�+��+��*�
X+��6}����
K�&��D_��g:������?^qrE���
�����H��Gx����y(8�,����P��dw�>B����D_>��{:�Yg�9�!/2hb�D�X���P~��4/F�x���}�r�s�}��]m~n��}���6�S7�p������$�����A�Ux|b�U$T�>_�ew0����8�����K�m�E�����K2��~�6U������0	��5�K��f��[�V6y�6�\?m>5��7���m��xW�Q��p*s@�U����2��	������
�3�p��h��|R�����L����_����ka�&�\��+��VVi,f�������$(���8���#����UAw��,"���s�	��HM��Ia�h���l����-#����9�M�}C$�E,�������8�:�P�.K�KJ���;�/(<�aI]���b�%�H��wp��)�'X��@�/AA]nK!�]����4O�i~������/*��684�Aw t�Rc�+���c����������~�KD"61�?��M(�q���i����.^1�-�n�xek1�3(���h�����R4���6�
�����f�=�3��@�PW;�������Z�
1�u��4���:8�OV���=�V�C���DO���V}�,�	<�r �3>7�L�u�)+ahc{Q7��Mg4���4�����y�2�rKH/>�f8k���	���.�4���� O���H����:Ky[�w�r�J�.�w����fMn{�@~��������[g��!���8)�����l����9����:�BD.��m�����<���D�C���d��N�v�����AY��t-VJ�'�o��c����8�G�F� ��S�����z�^���pn'`����ursk�rlK�����%��6o�������rb(BuW{��fek������p=hk�2�0�439��%��/�I�~��.xf]���D�iuT^�P�$�M�������f��:~��k������
����!��������2c��0�Z���3������v���5���K1i����Ol���Pb0���T�b�Sz�3�R���w�.�q�%�?+�	ST�o?����K#:\�L����vxG��H<��������Q��=]XA�iS���6��O,�2���U�Q�w����,�RS
�a�,J��3���<��8e�������u����cs#|���/���?�T.�]e�d���9��pv�����M��
T�,W%����Y�F���]�nQ7���IH��#�����s�
��u�wR�z\MY'i(�iO�@�;��(���:h�����������OA�<�z����`���R]���n�tV`;����	^3���e�D��V��u�5����q��hbe�;#}'��
�^!O�I�}jQIgL�~3u���&��!5N�����~&7��b��W$7�X49��T������H�����{�vC���, �s�c�����n�m����Xe	��Q��X8g�t��YV�u��Y�^�uvj]�<,�PE�WoQ��|^�>��V�`���R�����Y��lu[���������1ic.��L�z�F@D&�)B�
e�����	2�Jc��Y���v���
c(@r(Os�!������t���Ir�q���/�$���lgN�����������~}�������D
P5U�$*1�\�����O}��8~�v��PFu ��r�LwC�
���	��M�D�`,n!a���~������3�3�r�
9���U�)�|�J������d��\B
t��Bv}��
���WM��e���8���h�"{��&�G�l�����CG���u�L��1yv�-E���� �>���D�~���	�/V6����(:�u�S�2�;�bX�o�-��
��
u/�%')t3�|z~�(�����dU������3X��fk�8�<�l@�jy9��IL�;�p� g5����?��R������,	�������CmU�6/L�]��������IA�	e|Z�7��CRM���R� {��!:mb
Ib|[Q��]z���JzQO���C/��F��P��O�}�*]�H��������N��z�S3W�F�*��2���8�o�I]G�c��da���E�vYx�*#��:��q����t�&Y;���V#D/���������������y�N�RQ��x��R��E;�j�cp����|�Uev�%?�F���j������D�����Dx�HD}#�:��|�W-2��l"�StwA���4���V����d8q�����5,�������h�P��pm�,�����JV�<����(I9�&�����'�?�[.���D+-N�{��(��:�})��L/�/���Zn�����l��+K)�L��U{Vb���<:(�:vu�]���53���P�z7����]�@���E.-E�[(��|/#0���9�"7�J�?�s����,�5�lM���g�A�E�M����:�_����"���@�"�";��F(1z�N��������:�i4)����W.�)f1K�=x�W��L�M���V�v�eE�<�G�,z3�~�7u]�x�Z��i��W���2�AH�x!T�'�
Y���O+iX���WH��.~m��&�w*A1��������v��_�K�{s"��	�"-��nY���P���T����V��|#��l�T���i���P�����E�����L�
�S� ������hMD/�9�k)4�s�=R�iD�e���
>2C�����ju#������}\�B	@/���|KT�b<#�I{��x}�-�����l������_�+��x��J��0�����7g$u����41�i���6W�������x��	�uhkY���:��.�M��_t�S9�7n�����W=�|m��"��O��!�A���$���)g���d1�B��8���A:�i��S�����/U��m�"$Z��oy,�])-$�8��X&[Q���\q�B_�r��U����?�U4?HV��r��H�K�r��H�?�!��������~}�W1��+J&mfJ����#��B�8�M���ZS�XR��&����3�%����u��.���_'�N:�e���������g��h�r���c��+�[��q��iwp�-b!������.���3�fMU�W��$��B��m�W���;$���S�������~��e���T-���������6�R1�[�M`F��=����
�P`kQ�=|���G���F*?�����5�o2��
�l3�h����m0T��B
y;xyziMZi#�,�LI�+l�3��)���ze�"�s��S��a�����?���i�OY����/��BbA�gg+!-��-�|��h��Rm��'_����\iCi���m�� �G��L=��d"o�GC�NF�"�;����sR}rfd�mPt,�x/���.Cz���X����p���X�=�B��b�["�I�(����r�c>z�$�L��(P�
��B��:�������Z���Xq!�#���4@f��T��?�]+�[^���t��~�������^
g�A+��;�^X2m�����DW�=F��]�jS{��|�-;�Cl����?��'TB>v.u�������7o�,\���g�:������B�:��!1;7����P��<��;��D�y�VC��~|��$�=]'�S���b�-����#�O��A���Hz'q>�E��'S�m������G����p�@p(�1�q��E�Ul1���m]f"H�f�d�,��W���S���������o 
��A�zL��Qsj)}�����E`Z����F��#�7O�>�o���_�_/y����$��G��F.���U�aK�:.�U&4R���cp&�~5~o4�P!�)���h�eAUg�C�C�4��L�:B��2#� ����d�1�1��_L�P���]_*@=S4ieW�B���C&�_��R�$zI@�kU,J��[����[N�p_�Ct-��6�M��I���N����c�	�~�h�A^4��<� �'80��:x8��!D� ��;L(�7�N�b\E���0��Ei�Et���2+���ffa�j�����5H�t%����"<�L8�2���K��D���!k���9/2��/����R�0i�W�n�\�xt�s\9����K�n�V�v���G�c�r�����B�.c���,�����P�u��vE#��Lr�,t~*����5�o�wya����6��<��x�f2�3,����F��Yv�Q�rO�7��s������<�It�#w�	]��O��iR�N�gP���1b�Ok���+��I��F6�1b�.�/��vw��:����o�p��>k�����%��XqO���O�9K�
d�\��������u�H�Qd��7o���!Cy���fal�y���A]�6�����P����g�N���1��]�l�ro��@E�����s3�\���7gSot2Rq��
��
X�y�W���m���CF�(���hG ��s��qjt[r�6��Svs!kno�1���"�,;�8S����N�1�U�~x9Ca�����V�5��U�g�b0���0KH�o'�'��:��o:�R��I/�8BC|�������0@v3���U�	�T���ut����1�����kS�����}QT��2�De9(�4|�A+D����1�bf��Y��-x�yNy�>+�.6���G�2������\�(�I=y�C��(��@�S�I�f��~�W-uG��T _q[�^���������O��*�r�@���x���zCR�N�\��Z:�:
���U��2��3�@�L9���J���\M�t��7�����1����A�r�d�K�O_+���#S�8�v���elYS���}3q�2{��Q��x.mT�}Q�B�}�/
�
�8�:t����w0TV�����qo�=x��I�B!�:}��3�bvB��z�S5
s
�U��
-����n������\��~g���T.���Gm(G]��4O����Dt�X���r@�m��/���a�@��$~*��S3^���N_|�2��Z�[v�v���5hxT(�<`���/�ON�����@�����������hBvuc�����5�`��kB��F�d����������q����;]o�
��T"w�����:Le��	)H��Jf%Kg���{(��:�i�ZC������~Z����QBM�a��1���#��w�V�jP�����ce����Qq��^<'��32��{�Ld|�c3��IY!����m�$�]"����uh�t:4���n9{���Ql�7�u���='�\��1;���q�0��5K���bV_�j+��R��TQ��d^�2�1��0���7�\T����t,n���%�%���*������G�u\�;������0�UMAxBr��W��(Z
A�N4�h
#���@����:.��A�����*�J��s��9�J��~���F�A�sO��:�>9^��
�X�T�/_Nb���LM�z�u;�
Y7����33�d���2G��A1�����t�t�b���20<�i���i���<p���/�����l$`N<4t�4�R7�x���7Z��PA�Tbr$K���q��B��6�H�#�[����� ]�����Q|��F}.����^�j��w:#�� M�p|��Ym�6�)r��5����/��H����WM�I�o��])S��)A*�@x�(�����6���Gy����1�m3�T�����c{
����^�RPDS+����=��M��+��L�h�h��T�`
����d�A�.��bc�TS����9�mfi��t�#�~K2�(��c�]��vR���18	����2�()l�<�l�����+�%0����p1���d��,s�������lX���U���s��Dhj"!����F����h�����_��`(n�|~0���B��hzgj���,�[p((�_y��
)pub�/���.�W����	M�������)�{�"��@o�\�^�}�G���T��#lI9<�A�~_"��JV1�.D�������%hP	!,�����E���P�}�B�@���i*���lN'H�/d��0W���'�!����	T�m�!Z/���=4-���">�A�b	��]`6������MI��������]�p*�+OO��I���y�|fJ�F��O�	c�^��EZi�{�!��_
�%o�H���4��b�rx	:��!�<�N�w��f����J3"}��V���Q�f�
�YOe_[}g�	��S92�r�m�������3}1F����OO���0u�Hk�������S�C�Z��
V�}�6�0IZT%�'F��8���$J����z���l�5��Q}d(�9�Ne�}�c8�r.O����xLR�RBI�*�f��_o?uR����Yd���`�V[�g�o�g�uT�D*$1��>"��4�{�$�������N��8Y��p���%P� ��#���aI��n`�\��NR?��0d!o��3������.L#��0�/z���n���@W�{p��]o�u����N�@L=�J�@&��gw��yTb�2D�c�N�IOV�.������V����CF����M�`��dhb�[u$�2�H[��j*IWM'�S�*��}�I2���jj���N�N[i��VM���"D��������8[���Z�|[�N�7�P�,b[s��I��Q"��
��Do��j���b��q��m�
�e���d��s�h���>�����fl7
%�����O�Za*�C����zIO���u�o����7��a�Sy487xQ����Qe�0�& I$�!Q{Q�#s��/�a� 84�� ���'��o��$�"r��N��p[�aVIy�q�Xk �����x�����,�,�`��@��+�Z���r,���3:��$K��dm�}�JS���^P��`3/\C��C�b�jK���N%���v�$=��<e���i�2�q2�;1��j�~!�
��%�x#���~�����*)���1�t��u����e#���	,�
����xa)G�L9N�����6��m�@L\rS�����)!��`*��m���((�|�
;�����m4!f��5�G�UK��(����mtUS��K��AE*�}7|bH
��a*��xFGw8�S}D����?��t�z��,�6d�^���~S$h_�t���Fr3����Xl�*��)x���-7�E|����G�����v(�\a���������� n=����A�gM����&E�UP�Y�zmb-#��;�"u�)b�f�_�?�r;�����?��i#7�J��dK�m�0n�TugT^*��J�4L�(���
 9��i��d��D�n5�/9V�!"��TT�W�2��P�2d[�kwyF�/T5���H�Y=q*�?���(��5�i+�F�TS&CIUH��e��.��}���48N�����2Ci�o8���C���i�N~yz�v�A�1�o�rv`j%�%G-���~�?OB5�$�e���y-������7,��erq_�^�j*y
�[��������&0h!"=�c���W���D�I����tJ�Kj��A�s�m=7I�,��b9(>Q7�2s��5s�q��j�#) �V��}�h�hy�$��![��-�]��]����S*�o/0v]++��&	|F��p����B�����]`��P:�M�l�\���f2\�+v��Q��2�@���
3��2�KR��m�z�;��h���|q��n�@;�|y)4���H���/�����te+T���X!��V��(�l��Y�\�j����U%�O�������E(d[�_i��[���R�.��csHG�TwIyL�\�T���jL��P�
 	M�K���KjB��u��'��]j�$M[��vG����IB���5�L5�&�e��J��TH@��p�G����a���S{�)��U�����!���Q����Y��V��E:I�� �bu,�������n��q�+NE������n�+6(�Y?D�}���$3S����4����b)�4���%OCf�������r�e!:an3�}S�yd�� �E'�
���m�$�������;x1
8|"�f��}��m9$�z����xl�8*���@�pPD�Q�>nT��V�F(5��'�c��:�� �D�����#v'�������<�������sI�'���A]��DMB�����JQA�b
��"�U;G9ucY��Fc����(��+�Kd��x�O*Z����IG{���r�C���+8���B��������+�����a�n/1!��%n(	���8�z����2��%l��/�������_ ���L84K�Y/�5�M[�N�Vqo��=�������b@'�bkRL�4(�-Z�����~��F��F��q�NCE ���L�O�k��%�,a��E�L�>���?��!�0���f"�!;'s�I|�VB�k:i\3hq���pU��T��8c5�s����Q3��JF_���Sm]g��W��1�m�u%��R�/Cy�g���^�c��I��J�X�j'�P������={_
54�w��vq2�tJ��fAX�4m}�Y��� ��HU�b�Dlr��f�d�m@_3���Va��Z|��
82�����*-e{|2K����`��7�m�&���@C�V2���"�����8�����s�9�C�cYUI�h�6z��0���f���|r���vJ���ZL�e�-=�W�Mv�J��,�M`"�4�d���|��� ��	��� \�fa��[����)��$���?�P�f�$�6+S�e�$
����[B@8JsyC�-��[�u^���x1�������\;~��,RA�Nz{ja���x���JGC���,BdB����Hsf��V���G��?�a��/&-�1�h�O�F3"���]�vMd����^�t��w\c��[���p_�YY]}�r,jmp6����-�4F[������Q��	�:����>���'w�� >��s�� rc\q�n���
�PBq����a8�����M��K�Z�=��[��W[8."��4F���<1��b�bq�@W�8�2�OD
��T�iz�h�<Mm_��*�����@xexM����qp<�&.6��
��Vr��<�X��;��c���iG��]�������)�SC���%�"��lkyo<Y�X���1k��M^4<5��)4P�����u*s��v�:$d�r�����\%�D�]|cr��:��z�P��?,:�*�hC2���	��]m�o8��-���]
��BF�4m:a���bRF�
���t�������v�\JFv*�����$oK����$���@C*C���d*���s=��Tj���j��'
@��&((D���p���*�@�\�<�`M�I�Tt�����s�W!���tCo7�?�(�{�Z�������t�!������!�I����>"c��������(���*g�':k_J�a7]R�yyD�����E���a����0E�[W������<���[�P��z��)�& �����g#������!��}=k2����o��Y��rv�m���p�/<���	YG�T�cZ��	�D�
BUm� `�6I������^,*
����-v����a��<�Q��.m�B��le�%J���``/,�Ij�������"B�zEQ�U��5$�T�+������T���	FP�N�VO<����q�i�q�2&���2�aH�	{�A��T�uCR��$Y�;�k��8�$�z�K��z��0�N2
+t���$��poC*E�D�P��Z�w��rG��*(kT����0GY����*.ef�n�\n+RaC��1�)Z���)������dnS�aFE�m�@�8�h�eA��d���H���.t�Vq#f�m�C��1�AX5T����P��X�ZxX��9"G@���"�9�����C�C}-a�!�������cD~����g�;����k��x�)!�/G��Dj�@�J]
�0�����D=S��,v����qC�'�7�]a�[
���a�`4��}$CT���l��|�Z�dNM�Hy�2�y����3��=
U�T��8�i����u�s�����x�z��vG�f�\Y��6)?^�1���= ��x����Gy41������.��V��o"L����������s�Y�U�#!�����#\_��4?��8�J�~��!3M-y�2��@j�����	��9rSw��D�X����[	"�f�����.�����T�R�~��F����	���3"�8����,��z����8)�������
����ie(�|a�����~�TM"
�'�-��������>�2A:�asr�p?*�m,}�����zv�0�esA�lx-z���tw��$>��������AU�kO��U��/W
/cz��n��A �!�#�K�K2sF�#��������� �i����R50�28���6yB�
����#i^���@��
�5stt��r:�,�S��j>
-�\M!��.�B��Fu�V-Ab�J����
~C+�t87���&e�S�z��L[�7�Y&�	������W��_��&��b��+e�������.�L�1!<1�����2����U l���YHZ]��1	^A|~"�X-c+\��_1`h���f�B]�6����P*�o8����nV��@Pz���A��6qa���@���lS8/��t���tm������T�5���>�w���2�q�!��yB@:dc���������BQ��d<z�L����6`6�:Y�~����%B0\p�B��ByGl�A����������c[�2-o�@�eD�a��N���.��T*�%��7��ro�5�j�d���������u���g�s��8�"}�A�������V2Fhx�y�6�R��2�{������1?T3����O����r�I[���"���T$�#c�����������o��@^X����3������B�7kR��H�9���T��r*��F-
�(�y���A(I5*�uF��8m�
E)1��ZPQn�����������p��F^�6��Q���}�E�-��Q����w8t�������}�D$��%#�2L����*��^�ALsI���?�U<"X�������PA���e��E~�������G���To}�]o\��1R���v������_��Q��C�0����� +���G� ��D0��i�bF��}��v���H�i�T�FE�y"F��D�c�*��LP�l��o�">Dq+*Dx�P�|�c��������L]���-~�/m������<U��	l��?"
�@�p:��-A+G
T8��X����F�q�)��I��AsE`�x��1�C/� �pvE����(o���@��a5�~/�~�<�3tiC[�(�J�P�k��6*��p��D��s�i&��J�c{�2,�X��tmN�c��1�J�t4�K���M]>�%�!��6b�vg
��,Z}�>v�r�P�v�8+q~���b�uF���e�0���-
(4�[��
u7���e�A���FD�m*F?�"�`����i�A>&}�������^���H�(��E��J���B<}����nzd G��0�2�_c|%(>J���FDjXA��
�bxe�������4�����P��
��um23��_K0�B"��P�;��[m�8��f�y����s��%T0��)�!�O���!Dd���B�kcT��G]p7�0����0uNu1)&1�<���.Y���S+�[����J�R�)dj���������s#��,��.GuR�\�m,��mE�����FN��]{D����7*@3��B���EhG�����V��c���Aw@��jSA\�L������=�T�e��n$�m�&b����R���A�XF��2v��#C�;�x��&G-h�}�6u�/��TO4��������M���������e`��Y�X�vz3m}��S�l�r��k�.EJ��W���0n?����F�&6/�V�Z�G�0f+��5ca,F*�S�����/:o��K.j���o�� ���;&z��
�������0�R�0� �W�yV�����V��go��.��|�3�m]
��g����B��y�B����q;�8�=Ve�o�t�W{��� ��oDGLC/���c��7Y��8���b�c�Qh��xp~�Uf
��3)�2����x,��3s��zSZ?H����)�	��8O�O�*.������V�����P���a*�G���sVm�T���v^6���$� z*��V�>�[���.'
�B4i/��
��-ku���@��/�L��f�%��r�7�.����7���T�W���������{�v:�O�����|7�<2Dv�~�k#�is�VD�Q��N�lo���d�h33k>)y��y��AkK�� \�<H�h��q����?����GT����l}��EZU�OisZ��T����p7��QlC���Uy8'�e��/��,�H�������:��.b�s����ex�G�ii�,��K���<9��DVJ��1�_��n�{������jn�vt�be� P�z��l�j�a����1��\P��8Gp@.���9(4O����cB���l!�����V%�������a��<@��F9+3II�{��z���P�t�6��
S�w��2�f���i<'�0�]�U�tz��,A���4��R>�#��fi(�'���s8���`�������z��"A���	hvR�\-��H����B�Z�1k]���.�-���1���t,;�����&W�8��"�,��;JD�mZo/��w�
!��j�%[mk*�S#��-u�y����m�0�-Ko�Rd�l3]k��$^�(l�y�s�����!��P1�����3�Dh�P��4{��g
�9����Xf�@���k�RI��e�V���bi2����s
��}f9���GF�>?���u[��}���������
cyE��0��u�$���3ZK������������*/�v�=��m�B�XFcu�-���:����`|��}���Rkv/����|��B�!�a���DN�_]�����f�Z����@�H*�t$�������p�Ex�p����}�Q��SwF;V�A�9?�B_�"�k����@F�SR��QQ[�?�=��
�*�M����B`�tKe���L^	����S�A>�oD8����DSD��;�3��F$/��`r 8(�5�9���)b]y�j9r�S�)�1HPa��8l�Q|�$�d��b��Qf+5�j���&���X���8PL��F�\��d
�����<�q?qI�c�g����"�S�-z>*����MbB���Q�qy`�<��J�rB��0?LL�'����s���:u���%��?�����qH��!�� �y�����n�J�����'=�Cs��(����'���R�A ���o�����QT������f|��y:����Y$D�`m���Y�C��NB�V�+����K1K�����������*ft�R�n��J"�NG"���u���i���`���P[q(��1���)F�B�q/���lNW�������o��@[�e�d�!���w}8s$��&u�m��L��CuC�k1�������w�PI��+[vs�7c�;U����AIn�'�
�_|�b��I�r�.z	g����_��_��r?!h�$<�^uK.��m� s��s�9��\�Ulx��y����k2/�Q�C���~��uisa$�'c6	a��@T=�IO���qD!���t$��*�W���dg���Ic��L�*�_+���(W~j]G������8�0�RmP����M�.��X�Z���~����#��-c�G���,���}(!��%k�����|�WG������!��E��DF�Y���!:Nh
���������i *�n0�81E	�����s�^����I�G�$���J�8��-�jR��Z2���J�0�)�������d���wKpSV%f,eb�Y���:"/�viRWc����Lj,&zo�ZF�h���^,�"x
�An����/�������`�=l�v��m���!_�B7F����|f�QN]-{���"��aF�2�(6��������<�s������X�"Xu>��}4��<�:��!kl��
�"7JVVK-S7�W�jn<�s�~M)[�[��O4��80����q�=9���3�u�r��!��6�p<y2<f���8
`L���]�P�>����PG�:����6�[ah��1�AW�3|��<�T���i9:��L_�������0��*N����QoO
D�g�-kt�-O���HG^M*	}�X���������h�O2X���
��L����/@�9�`�a�[f��.�V���>;CX�SG2�V��r[�:$��1(�V������KFi���zr�	���Pz�Q�>��^���*��e����8o
$�'�9��
S[P�bPF��rj:F�8�T1�gg'��b�Y%�����v�-:LT��,�����=�\\vAZ����y��A���6M*�����h� ���Sq��~���Lx�)�=����;Q~�/��o���p++c�>�� �D�z�:�5�)��N�bm��D���qwH=�:|o2��o@�>���r�j�7��P������;��T=�lL���F'��`���&t�� �X�����5��UE�T:�%fm	�(e>q
�����e�<z:*��A��!^������T��H9q�p��$��7���!�qq"!���+%E{�������|����{Y{)z��b^��[��?~�����,����
���7u��3�F����)�j3�b���)��������*K����TEz��H
f���o,Pp��p��������������Z���(�v�������Fca��|��>���|<����o16mb�dn�|�C��F���*8���`��L/���.��]�@tA���l~O����q�0u��[�z>f��}��Tk&�oN��^���ReV������F��Q4E%��x;yY0*G�LG���2��~3�&t[����1����A�2�g�l��PA�7�03iq�����G�u��,�>O��bm9��N�#���"�e��I�c���}.G��<3�J2�C�����
������*�������8oT}������A���ppvy-p[�ih�0a�eU%����H��X�^�!}�t����T<���vOM�V�l?N�7��z�L�@��I��D�u�O�����b�Q��f���z[����i\T��|i59�T0�[�c2�'��d��M������!�3
�{n<���GE�sm�%�V�=���]�]@7����9�D�,�����9����('������A��/����J��5�R���m@>��n��0�/x����~�fK���h�����'A9i�2�gP_C�:��DL�����$�����_��_���
*�r���Z9�D�V�^��&I���2���:mZ��
��a@��7+����8�:�j08� ���M��e?��y��9m4hH�=j��F������|�����������e
A�.�}K=\$�+��.������pH2���#���M��^k����U���g���d`#�{h�H4(�H����<�4�E�L4��0��5���!|����6e��;���9�J����-=,��~:��N���Ng���^j����^��B�1���6�Z�l���]��>2�Jt>NU(�Ag�vr'A������!^��[�[��K�f`���d;��dnI��h�D�S�������'�����y&s��Y���0�-��"������Yhmnm�-�|v���Iq8�>&B8tG��/��u��0KSh�2�%1N���v�VS7`.��s�b��e����5F��e� g��c�_K%�<;��@��sRS�U�
C���]E��>LG9���[oV�)�c�Ic�K�z�Z�=���yV"R~%k�����<&��~ a,����a�%/��(u6�2���ZeX��!���G��n����d�tS�ILA4R7�x����3�DK����g ;4f�� l	
�Y2�7Z��J9���
���
S����[h�:a,�'���;����A<,��a-��:�<����T�Q�B�9��N�|���`��'E!{����{��Ab����e.����}X%9	��
�-����1o��rK�����)Z#�;���Y]z��V���Y�+�v�����NYw��8�����2��9����8@���CJ�#����W=����&�u�k�� �#����CF�f��t��)D��/��z�D�+�����X&;�K��h�&\{��AhS���.�yT��Z�:��m��L`�e�s������S�c�RwyX�F`������e����Q,��v�S�.�������88Fxxkt������&��&e��5�hy��u������z`�Q����%�`)b��Q��S�17��a`s�.]
�����Y*<�s
L����25&�Q��F=
N���k���|�M�Qf����"T�%�}WsW���@�����������A��m3�VR���b9�R&R��8����.�N[�I�S?����F7�t1V��=N��������l6g�6�6���xJ���� S3Xh�T4G�c}u��7����z]�	t�k�i'u�\�T}���s�x"��B7�*�i�, /���+��!|3�r!�L�}��WA6�J@k����K�� ����} c`e]^��u��>����R�����]��|�*�{K�OGO�%]�c���c���`�v���?�d�*s�YRq����G]�AE���8�<�\f���kW���
�E:�r��B}ye1/�e.�_,TgW�J�5cn��u���T
������T�0**����lS�y�s�+��:b�M����it��.a�
�=KC�E�@[wdC�)��c��1�}�A@B���KQ��#�SL��l�V�}�?1�v�h2�������dg)�Wz�����������q7�h����}���)�_"0U&-GYZ�Z-�?(�P�p��N�fm����l��mn��I���h���@:�r���IH�����:�cm9�
����[�!h���K��QJ*�s%YN|@%�hzB6�[E���c"~h77i�!�FD]O��6��v9�iY�{����
���a��iB�0c���� �24�e�)�>'��l;���>�J���2DS�_kT�s>� ���B_1 ���NDh��B�:&�Z`�*GQ�X&��V�q����G
4*�_GD'uo
L.D�G"�a�!�K�C�I�����\j���N*#�_�Z
nH2��	1���$���(Z��������yvf���H��n�C.EJ���F}/�fMHa����9P;����i�0�+���(0&�����r�xuuID�����S*_�`^^��I�7v�
���z�� ���U�f�A���WL��x�"�C�����0�p�\L
}J2�21��D�"����y��h`��p	�4TX���z��!�h"S��,%"�b���5��VeV�n�gW�8��	��������@���`���\3�,	c�j���O:�O2�
��:����e���{��"f�/��.0��=`_6�	���k&�N�!/?y�2F���h� #5@�'�=M�4��-BD@.������5��P���t�����S��HNK����`�L�J�]��o�T�RWb?�^b��Tap�����K=��+�Z���,�P���<����?h�k���k
�D �
��,C����!��.3�h5���� c�o�z5�����g�����I+�����Z�Yd�4C��B��Zh
vr5E��<hQiY���Xo>
�UM��<���$���������d�c{lL��d:I��=����y����#�ld�0M$�*nYW�����>J�Y��):�ZG\�1������C ��Q��3��z(G��;�Bf�������fQ����p������_
y8}Q�J3�[��������!���Z]�1��E���p���H���e����A<��d�fpb�)fG��y����f���)���a�1	�*����|K=&��N� b����U���*
seV�?�*�L�Z�B(�>B=��t�����.y�j�(Y7�{��'�-G�C|�
��|p��j*tS1��'��@qu R!nbF6�3�8 �6�k10��w�n��<NO
"�	�C`��{7mN�2si���P|��X|���;�����P��[�o��Tw�A����f�c��� k3��m6���(���4%�����(�W���{���C�Q.u��HQ��D8=�T~�[r|(�cAd�Cqt�[��=`���z/�;{
NI����t����R�d��>���9<�z�S�����AK`����1���x��,:	�2a���R�(n�w�J��HU{R>�'��N��U 
B9Z��n�z����?�_r=u�_�P��2|�x�(�����q,���q"�Vc��V�0��v��Z�C=� �*X����d��]5���{�m��)�#�+ka��a��i:*�CE?Uh���n��c���Z�5�P"D��`�3���������+J�?z|�O���'��}�����g�0O56O�k�'����7�[������=}���������3Q��Q?}�s[�i�*�����E��/���l���G}h�O�����_�����7����z2������/�-u���b��:�Ji�������z=�cw�^}��Oj��l��?=r�?>���� �����~ =�����S^�������X���1��;���R��Wp)��O����>��ZO�~IrE�Guj�\�1��a�[�����i�!O��m��������"�,�����O�1�g�ah>"����*�Y�a������9�U�d������qcC{��g�]d�%�� ��/��T���`3���z�|�u��p�:���"��\�;�zu)�c�/��A����b��h�*]?������_���{}�c�����-j�di���C-���?�.{������z���oe�3x� d��
�]����0U�����?k/&/��O����U�%�����k�7�?���Up������Ji�#����t,��t@����}����������O��_�|��~x�<��������
+��<��^�>=<~�����>=��/�5A�E=J�^�����;=����t�����������d��J?>�g}�~A�O��M\6����a����������i�?����Y��L8�kG���K;��������}���W�6�S����7��	�������}B�9�~y����&�x���� [z�8��������E���������t����L�s�`���O���:7�:�}
8L~��D}��]P������P8��%}{��,T���B
p�(C�g��B
V����P�����.�e�_���jNQ�����Q����.R��{h����:�ib��WZ�{���]����Q���(C���XB��������u�XY��v_�����8�o�'�������\��O_��B��\�	L�A��!=�'{s�����~��B�I`O|0l�|R4g�������qE~����M�������)�	�����)�(����\/�l�Uy�~x�����C������#<���8�&��'����S����O���s�Y���OB��������cry��a�T��OJ��w��g���|#���T��>u7�������S�V@Z�&x�Td���+��(I��;��t~����;�[:�������D�*��N��I`���U�C�+G�1���Qp��i��������������>��������W7���+u���,;����a*�A0��_j�TEO��D��eT�[���7��,d{���d6���IT:�#�;�d@��P�ai�S��&�c ����g���4v\�Lm�y8����[��J�YA��]�OUW�'���
w���m�h��pK����V�<�Z`~]��eW�<\��*�NB!��[�~3�r���eg����0i��H��HH��*L�mr ���
(`��,g;��������8�h{He{�l�E],���TY�aj�N����rW|y��SB�!B���C�I�ja�[�g�m���.����qkN&|�{/9Lz� �q)�IblF������WS�M���*#Up���y���������3T����4f4�Gv��� ;�l�j��=�I�/.7�@j�
����X=R���
M�CW6���f~��7��wftt2��l/s+'tQ�w��Cf�3:c�
{c�i�:���=zl4x���+����s�t�[���bk)�mg����^%��%�B�Fc���"�@���O1`N�&x[��KLO�)�wdG���RW�
�{He�K���l��q�E�C
tFC�l�V����������`�^=�e��9O�yB[�Vq��LS���}u�kpD���Q������"���q���Y�O�=��&�����N�����"�uv)�<�6�� ���1b�{���7>�����:D-����O��uZ������p��:�=V��dV����f }�������2�1�2/f/9��,�$	
�:�[��~�V��]�OfH�0�K[�[���/����c:&N�6f�����l	�z�B�n
���~�u�
�:���:*�����>��/?>>���_U�����nQ�
SB��2��{kb6��i��������hq/��Pg
����q���Q�[��1�����E����hh3c�@:�y���U���r��J��%�Ge�g�A()���%��]���Z�/>B:$����zc���,�eJ!��_�"'��+��g��u�O����D����R�ZO0��G�L��z��L���i��%�6�N�Q����	����8#-�����f{�1���1\~yW^7X�o�t���>�(1]>T���Tq�mgq?��w?��j��������������
?��@S�����������PDENu!�fC������|���!N���q�js��:O�VV��?v8�>�D��SO���S�-���-��	��f.����_�j6?�,X�sl�#t�u��0e�%um�Ksm�n����33"((�f�u����Lb����v(���+��:�SO8�!�������}���OA���/���:�@���G��P ��Xb�#�W��]J���,"�cQ�j���!
���A����������s���v�'����Q6�}���/+�s��H���+��`v�A�����.��d�.3i�4�M��m��_��P'�,
X_��s	�(I
j���][���;�{�N��W��NP	n��D�QA�
_<SG����^y��(7�M���b������tV�e�0����ng.�y&u��\��1�����O1��[N����l�w��o�$<����m)AS��
u��c
�v>��=}�]�����D���!�>�k	{7��9��^��d��
����X��Z�a;1;�T�R��fb����7v��g�Cc]�h`l��=�a?`���&����p�gv�*���bR��,*
�����
�W������c6^�Y������UD8 px�W8����f;�������9�.T�[�*/K�/�;GM3[�����&���/�?b����v��
$�/��e�H�I^A����e-�X�<�2SR����p:�'��l�#��_W��<s�k���=�������?���������O��%|�~HO�>'����"���"��v
[a�Q�ht���9��"JcR{j�������v�k�i�~�/�T���*F���*��*�����5��A}�s���KJ�����av�,�]�}��,��m�^Ldc]��D��V��l5_��L��:��R��K
/,������iUqy��]3�l�����1�m�z���fMd��N�`�=�Y���q��<[~���\�l[~|D������������u%5R��/�R�;NJB�*���6&'F��������>����]��&��[��(�������R����`�:��yjH��#*2H|l��(5�����(��\UB^2�x�~ c�
%��+x����{&�de��LGe����.�>[1v�Y3i�L_�*��&�U���0��,�����w�;����(��z���������,k����UU��B��VzlxWt}��l�A�zK�
h�@�'��N�P�a��[_�R����2��U;{V���r�T����]�P�D,I�
:1������j�vHW�-�E>��'I; _���*<L{�Ct����q��7G��r�b�~v����u�v�Vg/��EX\����Y�#ii#
0m�N���7:UL��>�A�TP�m�v��{���z�]-�=�g��S������1���A#����(D4�B��T.����C�MA��k0��7'�������#�U{�6L�Ja�o��U���(�G��j�._���S�����b��:����n���6vj-Ptxv%��j'iC6����������v�)�S��+�:��Gy�;�0��i���;��!���W�7Ejtm@��K�@c1a�X���b�rx���I+M�P�
�~���ZvUv�Q��S������im��0u������a2�o�
��|��X��n��4i��
���y�\�S�_����;(��vl�6��I���4��2{�}�l��(F��w �D��!Z��be���8��u���sLo��W�%���/�W�����PFm|���\��t
�Sf����,�JH -*�@������B�r�K��6�Q �xm��z0d��~0na�1_����IUv����T3Ye�u���"K����(�+��L�#��]r�
>a0R����BCZ�a�����?'yyq�#Rz�l�=�t����"���V�e�S��qQ�A�S�3���3�v���nI���W���S$���q-#Y�T%���<�2���`[��,�T�1��sy�9�U�jE��'�(v*|�������&����u��OS[E��A�c;\\�:\�g���Lu�]���D9���#I�"���tr�!,M��D"wR�~z��@R�����>'�z�
dFY���������S�s��
�4V�84�P\O��$���s��u��4��u��B��n�[b�;;��E3��������(�oo|����}8WG����Y�x��HX��������^V=��Hg�0��Y��%c>��Z
@��N8�T��}|�{�3����+x�i���f|��K���HO��;$��o��k6O��lS��?�GG���=f����H�(��������%�Pb�kp���7����V^Q%��LW@B����P���M���3g�5����f%]	�>�BW��m+�5���������`;A�h���-����E�Y��q�C*��"����/�O�����i�p�(�9�M$�%8'��.:4���1,ytVTY���M����<����D>�
�?!8\K0��pN�G�7����WmQh���^�.�-��$��:$uO��5g�U��������@���F}���C���D��n���|Z�g)���+SA�p�����S\���R���(-�C����C����BYT���!<��Q����u���-��^����G�))���o�d����wMS:	
����F��W��b�~�`~��%,�p�T;d_H�!�&�L��j���[���dn�=ES���D���j^�U���r�b����������3?*Ju]��Vy���U-:�`�-��G!��o��Nq[	�$�%1c�5��w ��"�4m���upd�g�^��Lu�C�2��d���K2��~����T�qX��Zo����nY������n+n���^�F��	�Fc�em��"�Wm���X,F=�����n��4�
NC��N�3i�3������8O#����4p#����Z���f���F��S���7Hch��8�:�u��:�1�#tqZ�k��BfV�yO��1��?��rI�����\�T�7)$m��F��������
&y���T��\g���x��g'��}�
���w���!u���|S�^�R�*IE�Y�re���}{�u*���(S>>+����������W�hC���	��o����]�w7���;��S�C2l7���{gZ���4NJ�<z��H<i�����������a(�{�{8O
���/���;�S�Y��Lrm��K�7���k��D�����Ky2Ci��<�����o
�t�6�W��25�!��������;b��K����I9.�����-�3�
d^������L���<K���P/.e6:=�����
��o�6�N������U�9��X�U���v��d��5(+l�>�������98��z�HT�yY�
�>o��E���T��?���:�
��(�z�Z�$+�IL0������O�E*vu9�����x�T������F'p�t�w����������=Jm�/�k����mg]T������U|�-r\)F�&��O��������lA�T�:����:��o�S�2���d��@D����L�!4��YK���3j�H-6���'8�^��Q9�a������.A��PuT:������HsF7�xL�{�ahI�2��������X������:��[�_L=�3��g���Hh�!�Un�Zw���������5���S���	��%1�aS�SJ���\G�D��yu�i���$���6����1����S����]�w�����G�x��+�����3��v�-�;L�D�@�����Jm������D�K��i-����2XG����m�?F��%(S6S{�{{Z�H|�j����z�4����������/n��	��\��W����u'"4e�S�E3����f��O��-.Y�f�}�[Oh��
����������*�N3SeGd��O1���<Mq�p]	Pa���?�o6��[�������t0`,���v-����)�M�X��p�����D�.'�M`"i�����~�N�[v���E�n;)���c��,f�J�M�7���l������"��'D�.3�Y��Q��i�pu����>��RN��������&��{�G�+�����!?|K�/__b>�k�67��]^}�����
K��K��:��0�N�)���`TP��Z<dc|&�i���@��2f�X���Yg_
*��O]{d]��'�VCM���_W��d"n`^w��u��%�{Oh�m����d��?���'d������m�x���������b��4�)���M�3-D�MlZ�:���������	O��7�h7�3!�[�#�����4����dX�IqSD�����XX��������(��2c�]�qu��6��[��V�a�< =�<���n��F	s�����05��A��`g�������l���<��/�~���/�/wk������������CT�h�m��Q-3S��@�^�~�q�Q�lC��:]�g�
���Y;���2�E�t
�K�*-�=g���b�~��-��b�1FV�:	8Ni���)�����������\����o����d�,�����/
�E=!1o�=�B9f����	w���J�33�c�`���M
���Tjo|G��X�O��%�n�0���q1����8f���\rx��V@M	������$���9�]�]H��*�!�o���09�����b�~�.w3u3��G<��[�?�����z9�������qX0#w���(�ua��&#yd��X�����r��C.�NG^�v�v��=5 xH@�Zy�Gt��@���;�����K|J=4�*������3A��Xl���7N���{(��}���	z���\ 6��j��
f����i,�����&f���Q8� M�)BN0�W8)�(%�$Y�������B����������.��)���h�u�YQ���nCT�Vt����
qi�a��S����
�>�5�ZDQ	�	&�VM��7S�&db�Q���o���|&`�.�HE��B��9�Jur������<ems�����i<~�:`�F�!������ d����e�a�����M�����Y�b7��O��}�p�����"�^c��3+5�a�W��]����w?��7n@[��9��Fv�k��V(�/�H ��.�e0��D��\�L��T����C���&��e�.�������4So:���a���f��Q�q����-���� �n&�g�g,�y����2��"o����g�����>`���/������VqV���Or��{
�f���V���6&�z��m+
3!�)�g	�B�B����" �o��������24SR������������$m��J�����q�����E�X!#��M��4VW+5��7%�J]Yr����0�S^�9�/f{kE���=���V�<njIOn��kT�E��S1���*��V�>R���y��������=�{ad�2�����v!�`%Qme#���;���/��9�\���R��d�G���v}$���l"�9��Es�t��"`��}��b������R�ErcK*g��rb0.�N��1P�=���I~�����=�����%�����^��xi��qfB	�N��K���^R6��nw� Uy�$�������:2o�f.B��9�5��F? xJ�V����1N9Wa�Gz����52��R�fc�������
foO�$R,u	L������D��v����P8Of����')m��G����B��oq�0�%�����n�����}-w7E�9����y��$��t@�e�~���u��i��uH�no��r��!�(�T�C��X��-Cf0��5pOW�m*�1#S�,�k28����G�!��������Bu���a��K4�j\��q9�y���< UG�9+f.�).-�H��1.TU��2}�V�yW�u�S-�"���/���������95qP����<><}NN�x.��'�n���H�e��zi+O�Z���Q����$������l����@?w�l���orF<���V ��z�����O_�����
x]��\Yg��Dj#���%�{����nUVAb��|2f�o����s��d96k�1x<����������p�{�xI��\!&��}[��v:�u�������(7��C�q�0Ld:�wP/R��������#���W���9�4��0q�j�ji��	������v�;����9o||W�o9����dJ��q�p�M���2Oq��osw�)�k�P���1�H��?����:d	�&�`e�]�������4{*ES4��;������yG��@c�zm^>7br��e#��!_hz1H�:��m	r\��U����U�&}����c1�J��]��\��s_B��XR�l�
Al��RA�p�����B�<�R%��Y��1���^���N��q�o�/�LZnMr ;=?����Qv.�|��X*(���AK���rB�/��{o�*��^�t��:�����\��`�I?�����$b]j�3�q�����>�k�o���V�,��7l�X�e
!Q9���?XR<�/Q���Yw$�
_H���'�_�h8�=���6a�:Cbsl��D�H0D]���Xg2TP���:G�3��iH������7{
O�s����B��HNR�6�$m���`���?��Z����B��69[3�� ������}�~��z�X���C����Ex��V>'PI�M�zR���<N*g�&c�HY�Y�[2���jX98���&��3�cmj��2��;���`���u��I������Qw����H@���/�C[pB�!������p#�{"��JH��PY]��~P�Z���	
��7�0����E3�������ch�,+����#Z��<�Px6&�����~�$���L4h�%e���f����*���g[,�z�?:��E���~������G�3�G��j����W!`��}�|��������?�&�����h�1��������<��o����B�^���>���r�3���*��bKj �;�i�{Tmv%)�*�7����w{���q
`+���T`�������%82��r�b�CM_�+���[��=��w
���P8*���c�j@�W%D�.e�\��)���vV��Q�W-8�X��� �}���H�����C�^XT��wG|�;K�n��0c>�s�����wr�I=5�����I(��n�I7��)���i��E(D��`@��V6~(V��{Fn�.�(���@�)��@��Zy����*&o���Q�,1p�x*[]l;w�9V���D4l2�wC����m���u5mg
K��m�-�@�����F\���=�c=����1��E��(���"'v�-X�������LC�'��d����>���>	O@�����=L��;�6��:m������	oA[=����%��C�8��v���e������A'Je���z�������_����O�8��U���E;�5�^Z��,��7�9�2W6�������6��M�CxB�qn�5�����#�}�Irkf��m�@���<��C!l'Kdq�;�Y�����)��bR���D��/bk���c6�R�F&�.�oP�5�_m3���x��
��:c�k��C����V��t<'oi�]��Xlz�W�CY�9���H��� �R:!��GR�r`���OT(��_�b�\PD��)����D�S@���<)�,{-�����y����,)��&U�M�`�6x50�s�H�uY9px{��MZp����A�GK~'�O��+�G��)N�cKA���<��~��S�UZV���/yJ����bS�'�}��G���]�7�#o�X��<� &��'�u��\���m6�(g��`M�J$@l���:��^�EM����)����v<�^��M�������U�������������}����R$���x������G�s�`��=������]�lUg6���������(n�My�L�\��F+����~dCAV�P�:`g���w�A17I�C��H����F�/�-9����hKTF���z ��8}���_H����YI�9q�0�/�c��$<Iy����A+�c<Cx�u�\Z�L����E}�?�C���1�{(��>8b�������y�>��JI�����'?r~�������$��+�X/��`���m.Au�;�`<D}H[�^���%����m<����7�������������:�>��_E5S�M���d�h&�������_3���w��wm'y��Q?$d��������STsJ^`{���t����'����o�h"�p8C�m��o���P��u�BcX����H!�nn���Q��HcTt���~��
??�����+	��vM&&mN�$��`3�i;�P�����D���Q �6av�0]����CCYf�����25o��o��x����g���0���� xfZ]�EG�����s��Tm&���5*1�!����s�a��p����D����y)������&
1����m���T^�8�^���q;�82�i]�"����r�B�[�4��s���_?��V��|�M2���]W�k}��@k����+�K@���ei��+X���$�����{�j���q9VM-�c���|@|�cvU��+�%:��w]�ZZ��\��9'�/x�p�%xcX[��0�"N��OdZ��l��ZK�8��+�0��K�;���#jCEd<S�N��[�E?5FI�M���Nr+���
o4���;Q�3�R�18�[r)z�x�h���<Ka>R�����h'�4s�Yw�����O���.����������
G�g��V����Q,U���w���M 'z���E���3?�	O=�����u��ke�`������d�1�4%d��������d��=���)1s����d]�d[�m��%��=q|&v0@���xY�Tw��`��dHf�Q�����[$$��z��/4�;S����~�~���%�1oI
���e�b���?����~��E����r���^s���
o0��5�{�)K�<��?-��]"gH�����	��#�7�rf�Yg�9�T�Xi)k�Kcf����r�m����2��G�X�;2�g�m8%!w;�}���$=�8�����~�!n/U�Ij�����	����yZ[�����}D%�F��*f��d�:�'�����c�[�
�X�w����7����V�'�6�m����@^b/��La^�vL���d�"���LE�����6�I'�����'���a��>_�`o�9??�O*�����5�k3�u?����,N'��to���M��t\��N�'/S\�vPE���O)��.�����j�d�PHC���=��k��U �3S�Q�'$fI�)��_��B����)�AK�o�9+�G�buK���6�
��hc�>�D-�K��X����SK�}���6k�~-k�S{�>5:�&�Ni�V��-ixk�BI��mH�-&[��$��a@��t��+����_V�6�%�h�����1Y&�& �}� ��m����A���X,�6Sbi��FA;l+������N�X�DEC���g����4�{�s���bl���*�m��r[�=J)�A ���&��.�~Hh{�2��C��<*�Gc�2�����u%'#��{�5F���M_~w���k.�L������������i_��#4:t�i�a�������a���'sK�"pK��h�9�$r��%Q�n�[����|r�\����4�����i �**�4��4�+�51H��U�4���S<��+UZXBY)4�+`S�+����k��o�f	��g��e�����U�z<i��x�!��0��e�^�#��"h�x�5�4����������������+m��2�L%
[[?T�����c��w�R�`<��7H�T����qW�)�C-�����>�
��_�yU�$���]���*�^�N������q����=H��4�t�]���Z����K��$��bo��!6cPq;RJcf,�������?}��������*on�bZ�D��(zR��&��������X�������A���II�	3}B�/���~m��r�G\���@�0�L�����4kz_���n9S��=��N��p�X����I��z�$��&9�[�8X$kr��8�f���02e�sL�+
��)����5t������C�Ha�o��M�������������@��"N{�( i�	����M�9��E�V�=�������u�����%��h��q?�=n�
�*�W��I:��cM�u����e��Y���X�uM[B���<WYf:l^��������xlt�(T^�X'����9�6���5�39�)��i�����h1e����Y����h�vc��u%R�W�_����M���'2���K8��%�����*:+���.5�=&/MU�~��.���3A�kgY�7+��*���h����-���O{!e�#a���� j7oz�4��Az�Io�.��+1��'���P�������������3�bf�"a����p����,�w��!7�,Z���P!�����od��!B�XYl��9�����m��T]��v�z,�+f/����%S����z�neu�e8��d������e�p�
���5����5���h�5��?�(f�8�i��6�X$�),�l��7�=������g���!�t��a{o���>��x��	�����h�I8!S�Jfr������8L�Te��y�����dZ���'E4�2�lm�Yl�XCU�P��@g�W�R[uO���������2��UT�5Y+����]���(������7��[��WTQ�I%G q��2=q5/���BT	y��Q��^�����y���)�l��q�+��oS}i;�L�w�(�J��Xmw'���|��[}�FK!;)���z�X��6h���_�h��^�����������4��)?p���wex
�Ag�UErz�%��
��Y�+� Ak�vc9��E��
�B���K�/x�H�|�j�<a��#3��*���8m�{q%�h��+��^u��WZ������D[h���l����RA���Fu}C*���a�aK{[�u�t��g�RN�Wh?�y(���H	���Im.���%	'-sd���6����>���c�b�����A�'�$�yg*|W{��>�r��r�Jp���ww�c�+(.;}�5�EA����l]����q�T��}���cs�>.��:b=bJ/��VQC����,��+�"{�[��\�?%^ZK=��3��7�M��WmH)��8'�����.�\��N��Q�������!Y�����%��T`M�3kH�G��T~��n���$�MS!8G��-j�abb3��m4�e��r� 
����
�6�e��5  �!����u��V����,����:h��M�I5���M�]����<��LziP����(�����H�{l�l �j.@%��,��~W�hM�3���j��@V=Xk� ������
-Q<��<X����/���}�X#�M��"�����^��-���RSLC$(f&�^[���O���X�q���EK2�w�*�����yy���������#��v;2���� ��}2�������R��?��-�F;��������������r���x�����'�[���6��*��!������Wj�����@�(���T�k��Vyh����*G�r)J���R0	�]�_��u>�x�"Xvw�0��>UY���tMf�F<��q��c���������i\"Xn�-m�������`������Er�2�$��1T��!�.1���F}�������?�65���O�Y�W���x��_��� �K���e%�K-����4���5�z�0a�I���_!dUk`�?�v��;��vdUk�pV3�1=���r��q��� v�J�sL��s����r�����	����|6�c�I��Rq�,��~$3V�����e���Xu)v�o��Fa�(�������8�r�7���1
8��S�c��!8��W���T-.�W�O������B42W%���^l#�i7s�U5&��m��5q��>Q�B������b��HU���H���}$�Q�4�y�Dl��1��hs��}k/0[g���K���b<U?��8�f�������/�����)����v�&M�B�����!K�.�D�p7?�kh��A��Ln�(=�{ �d�����^n��4t^���B�><���2���2�8L�F�����6�����z�����4=��������~L���4��Us�������cbX��!���T��'Br�A�$S��BY���1:\�4U��*�O��!-v�B��@
V�gA(�O�������I7��3��Oj�&���<K�7H�I�5yG���Lr(���b�k�T
�^�2K��>�-Z�����������*O����v�a��E���"U+i��c�${h��Rzl;c�%��M}p�����!�_�Vc8�J
�|o�g�����H$��������-�U��	!��
���D4�(��I�2vb�JQ�����U
VE��`�U��M������g~fb�� �G���KG�0v�Y88���I{��m���N
�&���x'B�H�N;�\��d�����A^�x���D-��M`�5	 �g��?X�|��z��Ri�8��$=A�h����������{=������AS4�8��uGG�{� �YS����2%A����wRO�#�c����V��Br]!5
���Ls��� ZntW��NT�����	2�M,��S��_�������_����g�%�����F��>�4�f,m��
�`P������{�f�+���T�goUw0qf�E��G�)HX�O��$���0�+I�s����)��O�j,��Fqit���9/��y����Hs��GO����Qs�2-����
�a
��`��|�����p
���c9oNO����]���v3��XuM�Z���us��F�B�P�3U�
[�|yA������a:
��P����h�[��7M�&����D�oRh�MP
fZ��Ai[hK����eS���8���R��e(�P��sP�r_-��6�t8N��'�)��~�J��(���}����G�M�*����IB��q	�����?u]����F�-js�g})A�J[��u�����f=�ez����v5�]���(�&�9�h-�CQ��&��E^�qZ�����u�F����$*U��}yQ����.��Dm^��m+�P��>-h�z���|+ds��$z�����`�VuWP�%�@������94�����j&!H�G�I�A^XS��B^�fZ7����HaO&��������&�w�amc��@1dk���|l��Y��B`4�s2����-��<���} ���A=n�D=�iH�|(�B�y��@<��=P�8�N�{O��y���������#��2����77H�|�.$d��gs_���l�7�
�^�~" ���o���)���{M�.T�DL[V]���M����0w��P�Ra%�G4���GG	4�M��>���g-��h�r�4n^��oR�q�g�jHs�X�gy������^i�-��K����X��dH"�u��Z��!L��^)O�W`�E]_IoVP��4�AR���+PF�W��&�r{,����c5�����,�2���F���6V����/V�/�lN����������*�e�<��	��K][���d���
h���5����?��`�.��O���Hw�~
c���H�6����������Dn����:� �A=�����8R��>�����X��s7��>zc�I��RHy�Pi�+������h�$z�O��:������6�6��(��m�N�	K7=�Y$����������E}��
��Ku��d�Q���FnV���d��gN=��3`��k{uJ������i��_E�����
�ImJ��Y����~.�"�F`V�c5:,���KQ96'{{?����\(�k)���E����P���D��4���G��?Qt����Ru>�SD���:�Q�����6<��JX���p$���(��Q���c��>������r����6����}+R���(�����M����]�D�]p��Ek�)�mID.��j*z���Rt�������]y���P�}�v������c*=����\��`�vH:q\p��C�J����jb{R��\����z��Ey�}`��,�/�������Al��>8�f|�Ok�4�/����qg�U�X&.a�
$��P����%610��a���2$ =U���!(C!'�4:`�w�!
��=��kNn��u����=4��;����ho���Sq���3-�(��~m�[��F�E�hR�n�����hw�A�<�D��T�cfrW��dyw�U����g����V��-��m�t��.��'g��
�f�#��-�	@oh
�Qq��g%�fs�z.�Bv��m��M���
'?�n�w=�q
$�Yv�n�XBec�4�������+�O�BN�Q�AF�����N�K�\�bh�U�EB3�R��q,�d��3���x@�y4P���O����<�G�:OchyL�
����zV2
.�@��W@�
�F��A_�dC\w�*�63��XV��{9/��#��F���;�(�M��N�&kM�f����SV����:�e|e�E)	5�6��������=��%������*�k��M��.H��-����|��tsUqCk���L����|P��S/ �9�rD�/���P&��0���.�4�A6���{���r����Iui3)�U��L���K��Dv9�
���
�����>Bk�sK%yD���=�~ ?���b�������3���.l�r8�v��./����;*X��2-�]�1=�FX��(��JU���i �qj�
�GsM'��LS�2'�^���'X��2�C`��Qz41#Y6�\f���m;�S&n]��u����F6��������XJ�gS�����GjWVM���8B�����\3�l�D}j��.x�($n/a���	���V�r�R;y7���;�E��z&������o���	4 �-u|����:����r�|�y��2�	2��}��U](Pu�yJ#��g������BrH�P�T>,&�����B}�8Oj[����HW���D�xp�6�r��+���m��\��o0qlO�]wT�mj�G�����8��yw�����7�~�1N�P�D��TO(*(6�������(#p�<,S��/�?���Q��p������O�
X����������^���>�'��I9���������PkT,�2���'�*�^^�O��?�/=P�Y{3?@����}`�F����_`��!��f�~��|$�������_�n3���6�!����"0�tc}%$��������M�}[�~��b��p�gi?_�Wcw��h#��u��V��S
_����<^L��09$|�m�a��8w����qqx�l����i	g+�Pr6|S�����:
8�Gg��h�J;��������O8-�>��o��9�9-����l���4����P���7�m��[�g�r��#kC���s<�{Q�hb�9{���M�H��HK8W}"�4�1MX�["9�4I9�[��4��pz52��o2b}�-�(l9}$����������I���&9�Yi�9
i�9����"����>>+�3���X��1����o-dG�����&�,yv
B>k�i�qN	�����w�`�7����VVp�o����������t���d��K8?
�>��jjQe��}��2�mv���������M�i{�y<���2����EV[+�g�{�x���B�������kK�����x��g2���F���6�`\��p���Nu��_|��*K!�fHx�N����E��u�E����G�������!h�L��=A;l�;VZ��J!i��8��8�m�s�H8��a�p��cwF����1mH�uz8��^��%��R��i�����I��w�Q��e*�,Jv���E?:Ox*���4A���\V��5gh��}q�B!������V7��&�&8+�d��0�'Y�e�����Qm�nF�	2���P�f�s�""��m�IKG!���SE��w��U�Ak��}�l4��f(j=�Y~�)�g�������5���<L�N��)
�t|E��v������Q��l�h���(�'m|���������p[��Va�u��e���_�����Vj�P��AE;��������^X%d_���Q�IQ�FKgN�A6S+�7����:L�P���
�/�MV�:����,#ftp����z,�$%yg�'vM^�m���1����]zrZ��&=��2 )u����pK���K[�5%?��;����|I����x%���1���LE=��a���p���V
[�Q����|b^#�������FB
��gL������	��Fg
�qw�&M��������ys�����b�l�h��W�i������E���;�����S���N�HwrH�#i�,�u'u��������n����D���w/�Tx4���bZ��8����_Q
�T��_sy�o��M,���7%Q�5&D�~�h�O	N��BI���D"f
s���:��1������}x:�?��ldJ�7_?
��.���N��Q��\B�C/�^�+�=J�����H�cq"iNge���f�4����������]������o���T�����Kzm
'=v��l���&�Cs�By$���4U�
&$e���
����/�����94���nhx�X���6��tdD�4	B��EICiDT��X�>,��a�� �n�+��M�jY*SeJa~�C��������>�H���h^V�X�IzQ��of�?���������O�l\eY���^��xHz8��F��H�,�f���R��],s�d��`����yW��$
�����7l��G���h�l��Q�M�G������%��H�'6�.��g�������N���F�{FZ4�0�����ah{�u��r���cG�Fi����G;��i.�E��7Z��|�Tp�B�1�i���!�&��h� �D�������A��[��c{6!3�gi����zM;�l�M��<��^�6j����M��F!��Q`�!�&�I6�K�G����mw�����l>y��|kA���q���#��l��7�4�Q86|k!����j������d��w>�h��i�c�-
���%|oz����Ld��|c*S�w�I �������Xi��4
#�u
4.��
�Y$��hK�������W�@������i�0��C���XF!S�C�?9�������./m�
s�c�d ��&�^5�	��$�����m�`�b(,h_L��f�"y����>h��t?���q^�k�I�9$u��	�p��P���AAR����/��%8"��1��(41�������d���W'�7=�6����	5��V�v������g���N����-:1��w�����>�������kL�����z�68M��iP�<����~���"
�[U~������(������
1�u[E��Pv�T"�������X-���ZE��}�������h�B4O����M�J�-���q��I�}m�
���Y,PVe�����@��x�$��~�aQ�n,�����i{4�q��e��,�k���@gKS%5��D���o��6���'�4�-�N"&ow\[�$�#�i����(���>��R.,�=/o�;��E}��v���bH���.[l���g�������\W��I5���RV��l�$�4�w����cY�P���PxJb��^������=�xC�g��*�PH����j����:]|5�i���%n�9��)8���1�h;��@�F�lZ�k*�h�

�T�I���� ��e����E�6�@��������@%-���h���v�2�7
� S���e0�0��}���	V�Eh*'-;r�� �N�Q.�x~��j
|oZ�7�F�yM����w�Q��~���L��0O�����s~��q���7�x�>������L~��\{����*�UI��-����})���}�D{�P�����8n���7h����^E2=Pi���w��L�xH�	��#=����|R��D-W�!a�0�X�0ekk��BVtQ�����Hb��l�<wQ=�u��)u��.�B�i2�G8#(
��=���'����x'hS!�F��R[T�z���D��O���:%-Rj�N;�e�Y��kmk��$�}����hZ��)���;f�I���]���
��V�2#:����F9�9O8"���D!����,v$�\v��!�U�����_�
����g�#WI[�0&,��5hl��(������!q�X�^�e����z�]�T����:�C+��'m������o/�:��:����G����Y���Vknh�5����G�k�^�����"�H�c&$�/�FaFTe�r����~�z�[IA}���PFG>���=���}�8`y��������XQ����I�U��a��'�Hm)E�6$���b��p���p�f�4�JP�F������e�2�v�~��J������,�&�Q�
�S}�_�j?k���~l�p���6^@cDx���9H�'t%dn���R��������p�q�{��IN�m~�q$qY�	�W�r�wBAM��`39H�;�����a�^�21���R��jZ��x\���j^���;7�)�(���g;�Y���O�'�j�IG7��4+�9���^�<���N��+�y��>;G�@;dB���!�-MT(7l4�mN���%�����A%M���f���F�w�0:2>[x8I��41�G!����ttK,����w�G���[!�Q��~|�Gr�:�������)o����TQ!��h	'/&��n�N�.��9��w�q��(d�UwM�[@}���)�e�K���!�2����)@XD����g��,O�`�����+�����4�����G�6�_v���e���!��j��S�5��a)Ss��	a9���O�G=7�q�����������=_�\/~���B�|��yt�J�E��)����������/z#�����p�L�^����Uh���@]<�G�p����EL(������Kl)��r�`p���U���NH���
�5��6a�1q8��4�um�����(��j�=��-�2����_��#Q��������L�@K��7(������}���=$��z}P�E�,.�	��$�M��?��4��oS�?Z��>:�H��>�H�_M�<����&�o�O�
�M~��tV��8��E.Ue!Y�S�W����d�Hyp��?M����H�F�TZ�!���Rn��m"�h�h���$��2�������`�E�mvb{� �����E�L�M�a�Z�Iw���n@k��h�=#��M&�o����k�mi��k�m��M��|c�i��G��d�q���e��l�����k���}��l"����� ��z���;I��)�1����4Z�1�Na���-���G�����������p(�"��C�yrh���K\V�E�|w��1
����M$
.����T�y���uc4a��h���2d8��x����������$c�neJ�����G_����w��<l�i\�5�����u��9������rSA���|�%:Qxdj��^�#K8��7�3m[�����wQ8>9���(I2�	�C�A��N#�I:K���M^wn����A��v�&�g�����6�6�4'���j�_�P@�mc9�� QV�I��j��Kr&� ��r���9D��}��F|��/:_�B�7�7
Lk�C1�6��	���>3��+�� "��,L��3�V�=��,'4��jkC��2<�p�R
�(#f$�SX�$�8s�����X���6w��GI��7���z��uO���*:�&nNU�!��H��K:0�$V�gi���Z�lT:��z���X��B
4H{[O5~�����.��f��1�q��F�H �`�yy�$�I_x$kz��;n���	OTP��e�s3�{�h7h��w^��8���.�McQF��������q.'/H
�i|���j^�4o�������Nz-�>df]9j�d�j�I��������@�i�>~W4zu�Hy[W�
�GAeE���k��)�5S�Zy��!�x��`���j����.����-��z��c+Z�����V����o��j�f�4��-������X��E�G�
��^�2�p��8���II]Qh�f�
W�B�g;�>� Y�1-�8i��6n_N���`�e|�(:���0A�h��d �4����@�ib���[�e}������{�(9)GDA��������n�DK�����?���h�����M���>�veNe��m
�f&u:H��M���W����_�������Oq�rW��_�c.+��o��<����]#�����y�y�t��sj�#����R�����w���7���G*�hh����F��
�qk�k��%�4=7TQw����7����������KN�-��a�kS$p!oG�u\��x�����o�p@c�D1��
��P�F�J�gMD��(�Q�\o@����s�����fnG!)�Q�������V���Xti�������p,��PuQ�>1�����J
�2�����&���4v�6*�2����Xsn���Bw	��X��o����?����XJ�E��� 9���!�/|$�-�6��K
���3A��=,�l'�o���O�h6�kzo�����t=����y�m6��Ohk�T��T���B�
�Y���N,��9	[�Tm������~({�(�MZ������6���w�E��]!!��C��M�����Q@����t����Z�9�-�z$q���a�
��v�v%�E}���:��&���ek�z��2����
�����L#�����?�4=vJ���Aq�
���y�H���5�-�����N����_p���������:u�. ������Py�5WQ��f��2G��h���8�{!yv�L��Vaf��������)!ae7}Y�S����HF	tHB��N���/���6�m��:�>�O����<�l;�����M�"F�~�1�����eb�i�H�
;(���8����N;�Q��p�7
������f��i�4�e�K�����Aw5
6���3�R�Ix�S2S4��,��@�|���X��K}��8eH�}$/�5:�P#��q�h���J�w���ZW��o�]Fx�s��goAZXe��&s��S[e��$��bl��l�<i0=�yvoEOV>����,Y����H����^�{��
d�vp��#?R�P�������$#PHC5�}��5����Vz����zX�4����)�'������(S���S8E��AZ���sSDdt�)��,'��5�"o�~2q&MPk�!������i�y��� �u��\8�/��� ������*�&�Le����o��M�e�������f���>����W��*�C�9����b�o��6��ki�
*�j(R��C�4�L	3��s���?<~)r�+?>�<�	&��@�6�DL"-=p�'-���Y��G�z���F����c����g�i�9_q���{�v����	���T�4�o�?(������L-��I&Er��A�`$mbk��y7����`v��H(Nj��1T��mu��dP�E_E|]yz�]�tQ��V�++��r�a$H��i��W�(E0N�+�7��h/U��n5vyP�OjDV�qW��������>%�t�ZA��d�j�`�X-Ky?4A�9�x,��
�5�R����u^x��p7~��~���3��<4���������%z�jh��v<��%Y�F�M)pL�*�mC
��^[V��Z��n�B����~��%����:
q��J xX\���-��
�=�����I�kO
p��
���A[j�8�@�%'b1��Z�xOJc����r7�mM�@lFSa��$1�-���xS�4'>�B�F��w�3���%Bt�}�;y��<�����F3~����!]��^����B/3A�������z,���/��TH�D�����id
�4Tcs��"Y�'���xU����p$��tl��,(������E_E�����z84n���C���Y$�q
+�����A�����6/��7P?��C<���X�F�@9��p��h�1�ECq���4� 3J���6^�-#	5������Jk����U����YF����'f>\<0B�������'D���*�/�����Rxfy�����K��v�q����k�7q�����$�L����oFm\�$�M6��d��J���M`�sM
�m?���=�
�H�.�IJ����`LN8�w�&\L�<��<)>[�'j��B D�f���9���Wc� ���������������3���yR<Y�	����0W �|5a)�E_���f7���pn��KG�w�3�`+�����y_A�-��e~���E����:h^*�PXm�J�:��W#�.#����7���yd������}f�w����e��L��.�T������������l���c�Pzb ��W�����\>�����<W�P���bzK�d��_��d����x>L�D<��}4�#]��-�Sl��N��Qz��3�7��mx|X�f����������C,�6���6Z�x�Yx�(���/y��r/�U�8�_��0;�C��A����=�����x�G�@*�����h�@���d.b5�cB��=�����K8���L��\�4$
�'�6���h6�a!3���D@��{�g4� ��==�����Gp������2a���L�WJ�F������d��]x��1��&�SL���(p���p3}�\����i3�]��f����b�2~�F;�_p?�0�>��a��L=<�-��(��y���4���W?�F��Z���`�$ �&l-�n[����Clhy����!t���/���zC���GWj� ���C>�g�g*�:���^��=������Z[D�MI����K���\f�<L��D"��|����a����co������4m��e,N�d�8���@��u
w�cA�<�"�wq4�{JO����y��e�	�����Pf��A�#��:��
�l��"�L�I,���w/�_|����) S�Q�%��W�����2�?����5��tV��_p�:]0��q������q�	I�5[�5��bFI+�
����H����H��h4fAA��or���Q:&�:e=$���vW�w^f���H�Ie4'�!�j�UNB�h��"P�O���L��L"�W����>���0�G��hJ��1�� NE����X,n9�I�3$4���B���c�1���lH���K �K��X�}�
tV��F����D��?=KQh��f���r�.���Iz���cEH�����F%iJ}������l�dND��{9!�E�u�&r�*]�����g�VE�G���v4p���U�H5=� ��m�j���4���xM@]��
����I�^�Y�H���}%#�4�9��7��c���Fm����m;�a�F��~�'���V�b�-����V���.�3[����w�q����o���D�}���+Y�%�D���Y-����k���A$^h;a.��C��G����*�>�4y�5�I��4�L@g
���K*������c����t��	`S ��{����{�v����x'��z����� ~GA�K���k�g,?�����4�!����qE�d���2��4:r���o��ES�#h��m������� ��l������BS��D�&y�7�]��ldJsh������0�;�"���s�,�]*�F>n��F�0r���rfVp��xtP���_����3��3{������}8[]NtU��8�4�2�^�ay������$j,���_��>�V�q���$.uW��f;�!!�L�9$i<��R�x����B�
���M�5/&N5
���iC����ly��� ��Y���P���pXs,������8�q^�l	u%C;'��3s��#���D~<��3���8�\=� �%UD6m�H
�X��	�i���`i��l�v�N��U�Xf��P����z&����B	P8z/@%�juo:�Ro�`���Zp��3���x�{p��z�[�����:�8�G����q��\)@�3�Y*^),�*�@�|����x7�W��[T���B./�v�G��H�I���~m
���	�������#&��Nrd��{�G���{�#Y&QS�j�W����M�\M�������zL([�3-����i^��V��"�8��;�maA��c����k��|!������`]�<[�D�����&
��!���Y@*/���i5�RY%�����mSu��T���o���y����1�p���54�	�H]nt��E|+h�O+K��Ee��}-���vQA��L�?���-�rz;������Q���u7�����T�
��L-��h��yS�b��jW������Oo��U�������V�y�&�&�.��@��N'J���������P�'�}Qw�?�UV���j+�8~�9��.�L�?�1����){{l��	����c����O�;�j���.]Vg������u����������+�i��!@5-���nm7z�|�����97n_[si	�r
�/��������;�N�!82d��C2��E;|��`KR�H�l��)�/����w����`�2lEIOS���?��BY:�0��E	�5�Q���FL4sMA%�/1�:4���m	�X�-���XT���>4g�������4Fb�z��5�;FV� I
b����L�������d�ZK�V��y2��2�0�WE���z���]^���D�L'Ts�(����(=+6�X�{x�����r���o�����&�B�������4f^��YJ�A������� G9&��X��d��v�By�����7����'$�A��*o�M4�tY����Kw��1\�9bF��nf�/�,��8��+�q��~W#�;�����|	#]$MW=;���g�h�,�"�������V5�>����YD/*4h����k~�����E���X���	��l����8t����<�PA����>M$Uok4��}E��8N��e{_����P�L<$��y
7�`�G���i��6�Sm��*��h��7��p���A���F��x�M����%��#��R�SG
�m���J��4���qm���S7	��OhE*?������/Y�������ox��lE��3��m:�M3�<��&o�����|"_�=���T�Ol��,�Q�M,�i@� -b ���^q%M�4�M������X;"gt�'�ufH����T�)�}W|�W������Y���?�����^��_���fn�@���Qg�*A�y��[Mg��}��SHz�i�O���2�^v �w�H�����4�eG2f�K��s�������kg�/J�<���D�LSo5d�������m�t-N~�����g=K4d2I��(����l�=Z'�8�f�Sga����]�H�
��g��R,���,�s#���(eBF��������
\]]���x��AE7]a����d�@��:}jqzK�^�e���h�~��/�A�rrx\�)�s6�C�����6��������}^����%�b�hKH�A!�-��}r���x�B�-r�4��\�z��X�	��fd���'R"��uW����.D`;�C��j���F������L�#�c�hg�k��'��������B�jJC�IH�:[���F��^�=n���=V�@�LA��]/��?��fb�3�x�U��m�A&C�@'�����s�ru���Zm�BJ<��K�Y����-�Qg���~.)`��Z��})����>�
�(y{;0��?K'�����O��s^[�Xc�z4���M���(W�e4p.�q|e��$:2s����4�s{gH�Ix�gyD2����*]W��& 	�_�Mg���<������x�'�J��`���"EcK����o9MY�����.z�EO����^j1P�y��JG��:{���]EeS}�������h*)�6���%` t9-�X��=t+�,���.���tj�������Q^8hLo�����x��TJN~��'���g���5��w6�It�CA�8��sk�Mfn��0�����S$��P��3�����B�,*o������H��T�z��'M��mjk�G��N��X��k�������*	'N
���"�iW:���G���K9x���VX�<z�8�!M��pF<���Ya�'}�,�'q�i���}E�v  ��`�k�����4�/�qu��4���n�s�O=���+}x�/��!����>��������x�=��]q���>����MO���h�6tOg=����~��5������v*6���A�r��Au������VO��� X���8��7����&o�*�����>��0
�HS��'���0�=���b�@B�>�H�4���Jh@I��yQW
Fy��� q���?yRL���$1���L��%K{K�R
��� ;��e�&\-�� N������E�E���lI�D����X�kO���h"�	h�\�T�g �U��#�l�I%���:�z�A^hA�E��H�Oi�#���i'����	��k�R���M<kQo}%�k��o��fn�L}��'��0Bnu�@Y�b��cf�<��oi[���p
���n�liK����#�`�@��)Eg���<
�#��b���^��)���s'�=�y��'m	w d�$��zT�H�����3�,Hl1��HiSo�&'��R=���^�i�5�V���U���JS������o���� m�u��i�(7]'�+��D����7x�R� ��!U�:�s���@�-��@�g��:�;6���~Y��&�)�P��z�ZjA�G]��J�A��,O@2�x\���
I���;H�(�A���@K�4�{y	M�r�1�`yH�������e��4���G�H����*I�����Pa�^+�bjh|�nU@��ok�����P����U`wei����~���T�!���d�&I9?o,;�r6F-��y	#\����|Q��7F���qk�,iTo�7���f-�}�{
�0����q�,�${��
!I�!s�m���c��@(��*�!�K#=R�\z����I�@������M��w(�-�#��~EaB����F1+���yEG��&��� Pl��}k.��8�Z�<OgtJ���R���*��>�o(����G�
K��ty����*��$�������������������{5�ZZ���7_�Ag�1]p��K�zk�����`�� V|oo���a
	�EK2$�b|C��3����p��B:��macI���w�[c@>����[(�k�cAp.)�~�`����yE��_���H6y
-v$bc:J7�3P����qS$�����S��$�ie�I�.�E��[-r�eQv��LP��>�!&��q:i�`o��=(

�p���7}��>;C1

T��e����
&��&�����A���r�qY�I�Z-�i&�$���������Qmu���,��J�������2bt@R�c�<�� /���������?����q
�h���i~
�@�K���v�:xS���p�&�
'�����$���1D^TS��!>�njk����m\�G2��
��5��<�8���Rj�����C���3���l�=��t�4�5�t������&����>>k�����f�y+��?���	�������(�>�5�;7�C8�
�p�!gs�`�G�2���������Zq��zj�h�|�?����	-������I']$�*�*
U_[�
�
�L_�Q��� zL�E�=OP?����~�A6@�������KP�\�����+0z��0�����4�'�T|WpMG�ba��/������E1�����+U��yu���z��Jv�Oo9u����B}�#��Ej=��]0�����%�H�IW�8�:)�I=uEp\�=�������zV!^!<��\b� Yv��h���\s�!��y>t��_|��N�����<�5���PXH������{S��
E�b!s��
�]l�������h������[m�%���U�{{$2�N�'`��q=Pm]r���I��0�4H'�ZT�1�a6"�7���IC
,������%��F��=��/�Ww��BV��C���'Q��l_4��_]%���p�������I�'������>���*/;���b��8+1���c���
l��4W�X���u�j��Px��r�#$�L�P��r�nDP8<V�D�e8'z��v���4���� ��!�Pz��U���@P�%���\��P����jl]#�9$�2��H Z�iVq�k�U�Y����_~��>=��nt��B����L�������������	�����_d��������sN��J�(�s����u���:��RS����}|'K��D~i��[�LT'�i/y�������O<��EL��C>F|��������������?��f���\��]��X��G��F'�����.��?���a���+|�r�������$����,�S	�����?���9���Y������U���|;���o4�6����&�����?�l�����E�,'����3��h�����>��e�^q���ws��/��q�:�
}X�8
�@��>�Y�j|L��?�r�<���x���O�O��X����*�4lI��O?��/�����rGZ�2	��G�����Dg����1���������:u�5-��j�<��wq�T>��}[#��4
�H�Ws���"�_T{��y����0�'���a�O?�+��_���9�j����l7��AB%��������+�����C\X�JR]�Z[���
V�k��mx��=�^/^�����V���3�-���i^�
��M<�|:q������>��C�s~��6���v��$gB#��4�99�oQ��DZA#Z�#�
G�h���Q�9
Q����
�������v��n�����i��w�i��Gm�&���&��p���hI�9���lCK�L9����We�o��(��n�$\�q4�d�o�����4<���#�H�l��f��e������9�aq�B���i��3�T����0���zMc�Hi�����^�i{�0�2��h�6$�2�7���������6�0��m0�zM��nA��#i��qem��w��>��u���Qz�BNK�i|�S�q��0d���a�9C�����;N����mx`�	����qm��u�&��&Yg����h��*��8w�h�9
ctE��R��Sd��q�2��~�8�B��\�W�9����i����
�Q���m���D	���<Qn��ueq����`�H�n8��6����~���hg�w��q�Y{������G�7=r�H�#���9��}�y���������(�a����
��<��HV��p����#��u`��4�9{����:=����4�{�t{�pz�G��Mc=������	�i�9f���E�8��$9���]9)�1=)��{�8��cvS����@c}6�(�8q��`���-'���9$�����5��$�6$a�9$��-Q��[��/$�I��QJ�����]����������\nY�����{��v����s���(VZ�i-�
/�sLC�����>Rz��!��\�)�^�&������MYo�S���b��Jr�7��9�i)����{g���1Z�d�a|�d�y���3����x�Q������O�^Mv�1�4�:�� �iv�3��j���S��;�������N5M�>[���+F5M��o��h���g-��
�24���o	4>�F�"Fk�i��Mm9g���������!�Q3A�o�5�1�4�7=����N3�4�1/Z�X�����]Fe|w�1c�]��f��^@��O3��4c���4�pMc�����"e��	@c]Y��Bvb�n'F������v��W�g��1���f����]F�X��������i��W4����#�6�*��8G!`���4�{gM�I �i����q���1�h���)`�i�4V�pz'�x�)8��8#�����RN��u�	���I�����1j�e�d������)a���jMc�6���s�'��>��; g���e��&���$��z
6�����-8�|u���f��vd��Ap��)ya������$�}��4��� #>k�i�#�%��=��9#�g���hs��a��=��s��*�|rM���!��~������/�F�+��n��/����i	_����|U$@���4-�,�a���U_�M�v���8�m��/h�=��<���l�E����v;lzw��Nz�����_�������O}q���q����p7� 4�;<V,�>��4���O���o���!��2p�s��:���d �J�C�	����v�<$5�i��uo��pz����K4�$#Z�q�Z��u�t�-6�����6.�N������yH���Yj�_O��[������*���j��.,�e�(T��E���ms�����
��.U�%�"M���bf�U��oL�g@=7�(8��3��!Y��G� @��}�A�Y�������#��(n�&����:<���i��G4���xD�ib�qS��m�0�����3�|���pA�u/�i�x�-�7m�#Z��Z�c��7�`�D[7z�d�����Z!��S)��x�{���#��O�<D��i;������(b@�R����<L��!��O��W���%m}�i���in�OKC��p�x�H���q��v�	����Q"���b8���O�C���t"��,d�W�3�"�������TI��{��w�������~_���}����y���#b�D���n�q����1�h������&��}@����V�w�?e���4��������tO��|~�ny�wnDm����3����v���z�B�WX53�����Up���k/�y���g�|��7���TJ��l��G���_6��h�1�[h[��m2�a�������?�^�Y��i��������*rEE�`���Kq4W�%�WTC�+T��sxHZtrI`hn)Z��J��\i?�.89��>s�14qt.ahIrp��Zx�1
O����h��$���N��#�u�-�w�W�>�vr��h����>�|�4�u�i��6��a�e4�u���.A`-t�j�hG�w�����(�����sD�h'�����8�4s�bh�=����	��?9E�04��R1��)���%��0M	�U�E��@�d�w�%�2W�/�����o�������-�o�i���m�GC��.�hMr�=}�[�Z	�h���VmOF[�2��,s��"h;��g�������*���X����g�w�������s�4�*�����.��Z��h�4(�	N��)������Q4��
��w6�F�v.���e�H{V�v8����314��|6Mc\�b�WV&��i�lI��)�P��Mr�}���K�Gs�Q��\b�(�b��2g����8#���x��4���}$-�>R�1��1a<����Z���.�<M��3D'�r�n�����[����;}��~A�\9�(����Gs%��h.qm���j�K�Gse��h�T�%2��q���K�E�7���
����Mw��Gs	ch�0c\����|z8S�Q8���5���Gs5���\��(�����)���q��"��OE��;��j���������������
��M wW�9���A������)����(hg�p<$�a���B�BW	E��7PH��1��WN�?MF���B���X1��j����d����\�M(Z:l/���2�����e���^n���A���2
���B���G�T�dxt�������"U�)(��e�U��M��v�l����{W�A;�3���v�8f�m��1��D�j���|3$9E;������Z���,�qe%"rI��h{FZ*�,�LT$RKniz���=�:l#��XC�����Y��j>���jJu��$����h����@M��K��N�����m��q���Y�R��������:9���L��!���*�X��/�h�/QD!
)���b�Cq�i.���[��W��_������B�j%�T�������H\�9�}����`���hu,��5	 ����gY�����[�XOY�T�>%�*(�"/�rf%L[�_)�Rtz�bQ�2�C�7���k^>���W��*m��fq^�]����������>���k��_2�k�Tq�gq_��#'�B���)��@z=���!���7���$��7�+/MUV�V5�	=������U5��@=��������
������n*�Z�B2{��>����k��M���5�q_�������+�L�!�U�^=��5��%��b�:!��'m�O�����h��+������Yv����z�_d�M��p�������_c�Qh�T/����U��H�L\���#r�����U���dO��@ZT/�.�.z����m�X���e���D�K��3V&uT�1-���l��A�h�H�}F�(K�`��x���]A�/�7
.y�u^�?�����3��Oj�H[x�#���Y�8�NVfL��%)��
g?����U7�/����$hS��9%��<���c�M�5�-�����P��R�Z���������WH�t��`J5*�gp�\61u�}�i�oH�	(��z�����I�Y9)���o�"/M}���{,��)��Hv�U_�O�tR@�^�X��vj����`w�������
8�3��	��>f��nO�&�f{6Z�������H��4�0Rh����%�B�5���X��@�v��p
M��Y�Z���=�%���u5V� ��L�7{w�l|����qv��!�����-���R�B�e�[1
���iPh��XM�B�8��F���-7R%�&7�D�(�c�i-�M���m4i9F��O[�Q����Z��8�U�H��Xg�D��u�Z���v:��FS�b�!Yx���hG�����'�qD�|;��C:V2��o�����������U^~���X���3�/����]?�VqQ7U���I�Y�7L{?{���r{1���}�;y������h���"��2���I�ij���M!j2�QEu�����/�_�L���/��t�Jmg/nDI�q}in�EY����'�K��l���������&�q	vD���������v���0����(m>`P��W�h)8yQ��������R���k�����e������<'��mv������fPn����dUy?7y7�hE�o��}�RK�r~�y�|.��i/��H�k+�U��./�����+k�
��c�QLb9���)�k,�4��k����Kd]E��q^����k3��z3���t�xt3�Kr�f8�Sk����g�P&W����'XrS�>�)i�����Kn���$	����D�������hu�R��M�+"1�3T��+*\���\W��q�������;@ ���TY*^8<YyME�\�{����cZ�t-��>Z�U9u4O�_�=����.�l ������B)M�1|t���@}�v�n��b2a���;q8��X��A�������im^��i��T�W��,x��=S�Y��F���=�u�lS�(����Kc�$I����%���m�I����Er%�W����qr�?�k<m����������������w3�K��}5�Y��`����a�l�>
���|�Tt$�������h������V��5L8H_ja|�����e��}�*O;{�T�q��/��Lq��O���~H�*?�b�W#_�}u�d^����������]&�k�!���,����z�o�vM���M��3���q<����9�9I��i]�'����y������]������NB*�V������?����$��4?�����h��:w��D���b�Z�u����&t�����^�h�g����D��m�I��|"�j��l��1�,Ms���8�#��XT�B��������8������m;�Z��v�2h�&���B�9F�	0+i��M�������|�M��S�����$�D��F{�����^�l�c�{
MF)���H���I���$Z&]g}���A�n��[j�X`�B���V�$�v,�L��y�r��H�h��(+i������9d|�c����=��u�R}���6�/���=��F;���	�l��XiG?���
4&fX�wZ��	'm�8�D������h>�|m���Z�q�H
-q�;-��;Me�S����'m���FK|��m'�)�}0�(��D8��$���q^�dm>(VZK+�h��i�h�BK�:=�h�B�@�I�8-	��4�2��y���V}����$�R�s����SN�n���"h8�6{��1�v�X*}�]�s^B�GA�7�f��i\6q9Q����"Q�J�&y�\j?N6�deg��
�4z���U�j>K���r��zmg�z2 ����������i�[���$/O��*A��&C7/ ��M$.'H���:lOY�}�YE����1lMl�������8��h�[�*�V�������v����s
-�v�����gM��ii&���kh�JI����~^wG;dr�������`M���)������>���c���"���{��"0�#���A^?!M�q#��pU���I
����z���d�"IPZ#:�Uk�T����tT�$����\��h/sY}H\��wVX��'6S ��_-UW�t���k)@�t�4o"�H��$�4�z}������z{4��e�����i���3��������_����&����*��7~��e�k20����O}o��Q����u�T/_�����n�����������j@���o���B�T~��F���dj��e
�g�x�������?=���j�������_6!X;1cS�a��A�8����{���.�iJ}���'B>��*J��e���Uyu���o�k�0o�
���*�m����C�.��RM����8n�����V
p����-�Cl��=���W����&D�A�]'�$W��Q���wc������-����8O��U}���i�{a�g8�}:�b���8��U���.�
j���g%�<��I7��Q0c�����1��*��U/���a����9���0T�y��d���	��U��>��>\5L��������?4�����~�r�`��^�vB��|�K�x��oc<V!��Ou����~���?�th��{���r��8��q�L�46�Y\�4�h�]�H��S��p��T��>$��A=�~+�T�:p��i�;����*Y��q�u�[��m=Q�����"�}��7���<H��yhc<�u{i@����Mv:���������g)me�}���*��y�N}z5�Z������n!�#L��x �8/�c�f���9dQ���9N�>����H���Wa�
�Ez��D?�E�q�q�=N��e����|�b�8�n��{S���ul_�Y���G��BW����O��%��!��o0���7}Ipw��������c����k���\�bO���'����`��Q�V&���B�@o�XMy5&E�1���.�q~�
Q_�qL~�a6��~����s���LW[]�i~�x>�O;n���j6�;-T���j���^����a�-X������W����J:�o��G0���K?>�`�������������|,N�p���36^P���
y��6����p��8�e�����M����n$�������������H����c�`5�za,������Ku�~��IV����H�<�cI���'����:������Ku������N��K�q�����09�$��-,G�J����v��W:����y��$ ���� ��k0�O_�2�V��@7��0����(;�Di�Cg�����Tk�1�O�i"ar��Z��������U�����_���J2G��&KJ���\3U,��C=��d1�z��qV3�AHh����e&D�E��
@/��k.tY�������l+�q��Y���]����vW9�Y����n�gV9�o�=K�&�,���1v�A�r��a�p�������G|(>�0X�/y����a����^���SC�@�N5�u�'�yz��p� �J�#����8)�#�����P�o6��w��g _��=��my�i�l��Y�/��}���8�^8D���9����OU�E����>�"I+��W^�z���!���C�dr2��2��Q9^dll%}V�!���k5�TPo^�
zJd����������1R�Ji�A���I{<[�Dn7�\(s�m����$-9���QI����0�*�is7s�-v���4��O�������k�Ln�)�jKjQ��>���p��bo�V�c���$�k���K��Q���>�o���6����F����{|��3���x�������x%[�]�r;�����l9��j�r�����|\��V@���ef�XT�z��B
�&rF��C�~�������I$G���)�2��Dk����-^�r�~��J�����Tf��P.|>�b��i� �?)54��Tj�Mf4^ey��]o�'7��hc3t��M�����������l�����Sgre.�|(�2gPJ���c(�C<����B�9�$>f�y?����*-k�v���U,���������#���c�W���w��)�7�Iz����c_���yX�Jx|��B����0��9��vl������/��Q�e��]!��\�	���'�S�������`����7�k�[��0�*Q\��^���I��:f�*�z�\��q1f���K�JW+_Z�����4��R����X��c1N���^�
�
1]hwcC�i����(��V%r���,�������Fc9���E�$jiw�~�P�mSL��3q������AP���[�l����uFO����>��5O���x��sn(6�/j���H�=>��K{��V|���k5-x�[&��Y6��st�!DF���>���H���&�����^���T��R�c��������U��l��j���(k���^��rX&/�+xj����q��b�t��.�dn[�������aQdg�&�w��*�,!�l��C���b���"H��A��]d7V"K8K:>�t�a�*�Q���mCFbD"��dP���`��".I���]��������^�O��qH)�b�������&�����em@bW;&��
��Q� ���5),m�Q��$Y��4�N1R\���!n7�R/W�x;����F��/�?sm,����y�]�<�Y�Re|�$��\*nu�3�_��G�:�E�^�R�kn(�E�XW���e�QMQn��"��&1qRts���2���'��C�y�z��;�����F`~#�	���]Z"���~���zQ��j�H"r3���FK
+�D*����*�DQ^� -�$k�wF�=+rW��)�S�-P<�����N]L�m��cL��|��fR�nZ���D5N�w��s�t��fWl�>�2��{�n[�h�d����;�?55���]������?���G��[YV��&�??tc5����^���s�V������T�f[�������E���I.�I*Y3�N�7*.Q�9Y��Z����eU&H�}R_���$Z����h����|n��n�M��E�s�:�����������(��M|]:�����d���C�cv����X�������n����lht�}��sU@O����YiF>Y��`�s*����Vw�.������rfI�o����|{Y:g�z%���[^������Z!����'*_/B����u����GI�	��P����C\V<�X����T+���PF}�5 �J�6��t�Pcz~^���o "es(�����f�����S�J����Vn8o5�+�Z�!�u8��q��E��$d'�~0Y�b��E���nps]�\�%��c���5w-{Q@��Z��	j��l�]��n=1���T�9����<�BF����������������Tu;�MU��y�
����K��_����_��'u�u�o���Z�$����������A@�6��-Y�����[�T�_M1l�(�����R�l;-�����z~��F��(V������:���0p���[r)zp&i_��;�'��Cy���W
���~O��R2U������������s��`�I�n�&7T�g�$>�
�T�p����dv��ChVWQ�M�'��Qqa�	`2��Y�L��F�N�n�O���~o�+�"����mI]�����N`\�}ZZ��c������C1���\�q�[��z3�JNh�>����EQ&k�������.�}}���89w��P��������q���,�P���TiNy�
\����?<��M$����[�:�����$���B�I�Y(6��4���
���c��g)���K�a�#7���������OB1���[�~*0�Ab�Y���s�H+����AUb�� �|8'���u���7�9�o�R�O�h\4_
����r~X9�U+��^BS�����������x�x�1�S�(�>V���#��:���b1]h��
8�TS5���m����c\J��X��WMh#���]zUB��Kj���V[
�%������y�Q���E^/�\�Z���L������m*A�]�����`�����)���xI���/�b��a�\��OA!��K��
��W[������g������v�v��Au�#9Y��rK�XyY�c����iv�����o�����m�.��,�3�j��_~I�s���0d�S�d�t"L�����=L�G:�dy�=��O�.�2��}��e��|`
IQk�s������P�L3���*�����].�t��n�:r��vK�!z���e�@Cx���NCj�T���"�}��$I�<�7��Y�R�0�>�:�H��;��g+�;�.VO�����K����:��1�81��RO�J4����
��#�`�F���:���
B��Q7�L_7�|�+lpn����
��-<3��^��W�7�~;� #^�������\��c�����l����}�*��@��;$������ J��R�������������4��������*���<B���O�1�
�k�^>���`������9���
�������%}���O?�|�]��
�=�SL��W@��DO�7��Pm���P�faY��q�s����!P~����7�k��!e�R�HCs�������o:������<:H��nu
�mmO�r�-�t�����h��r�.6�DtF�������&�$��9i�B���RJ�
F%W��U�3)+����R���k��s@���y��A�ARg��A+c���Q���1J�;*����l+e7�_E<lA���a�:��������x���9�@R����e�,#foG`�"w�����Z��M��O��F�����K������0�����Y\�����������I����V���lw]I�fw9������G�����s�g����I�&�h�5vWD����#�)KO��;c�
�
��M���<
k����\"��C�����WtK�����5�Wxx�����q@X��������4�3�?��,�v`��T�����+���K�������%0�s�;�N������{.���U���9l'�^6<�o3�X@�����p@h�=9=�|i?.x����M��L<�-
���Lbb�n�-0��R��pZ�����1������I���0�'N��I�����q��#>9w�N-*�x��S���To����&�p�\���{����D�T;��ME���N������i�T��6@��_���U��;���^��z�v��-L�i.�m���6��;{m�D��xO���H��D���"�����K�JR�RE�R��D��t?������`�I�D�]jL��nu<�^
�\@�7��O-��1��n����+t[�Y��Ij�!����F��eJ��7�5�"������;��~��l��.K)���ipN��$��f�7�9{�Q�B�����V�-�KrR�`��s�Btw��@e���L.�Rt�C��\G���U�<<���a "��=����1H��vDC��U�����������>3ll�[&O?�,�i�u?]
!�fh�Q�s��'�h����:�2�����BDg�7fUZ������T�~�T��"��D����<��U�O����a���nj��A�,�����O�� �w��QZK������J�P�9+��a�x����c�C�8������b���
��)X�N��1��.
!�j�h^�dzX���d�����E6������>G�>oK�)'����{��<�1(�+��7e���8����G���V�'ka[t�� ��%j��Kwxs	(���<d������c({@`3m��,�B��U�1�KDiF�X2'�����!���J?F=���|�z�/y`(/�s�������q��!���	�&���G����N��Vg�C��Pj�CiN"_��Vu���~�KS���)�;|(+�Z�j���J��B��_C��Y
�h�8�����(��T��V"�z�R��%`�������C1�������'���>U����q�N0
�����h�,������hD�`�k�2�d��>���"�����HKp�Ys"I�S�6�V[��DP"��@��
�pl]2+��y��I�ZFsV���D7�^��Sj�4g1�������T���!��n���|fa��;i4\�&7����&�p���D�&7*�z��m��4��&Z��p�%��bA�I��;QgBt3�����_%D��Wj�L%����t�$m������n��y����������9=m�m:���1�1����}z4^��Q��K�����s����M���$��]�}�
�~�*�<I�WdTw�kZ/���yV�����\�e��aG�Y�|U�+[6�v��?'�/�&���/�J��c�MQ��h�������Z����������'�	O���rl0�F��������Qe�9Q�
�V.����I�
�������#��h�^O������|4aN�����:y��m/B���s�F��g�7�B����cbk����v��}�)d�����Uc��|��i#sC7�x�lZ���|b�@d������2@�����E����s�fj_%�5����O&e[:�me+B���LA�Q�"�>�+
�<�H���&41\�����;�{�0dj��R�a�5������(!W��#x)�����D����VvY��N+y��z�H��5����8F��2/����:�&m)�F�/��
NX1��`�X�'�����Q�G�l'���f�������t��[����F��Y���<��yM0`��E@<���y�����Co�(�����c[����~M��l���!��O��wh�S���6��`�Y��7%�����Rm��#aa8>��Ob�"dz���R/X*��.�S�����������5�����6��L����~*T2�td=�w9N�|��� �YN����Kw���$����.��ir��6D�����-����}Rm�NI��q$������}x�?]���j�����8����>3V�������q�A9$fa�X�� ��_��9tE�.[u�� ���s1?s:��,���jpm�0�X<Z�����:c����������OG�A��{�#��*
>�R��9�K/,J:�8�"�&���d��s�5�N����P=��~x�����/'��f����j������d[Z3U�bi�*d��u
���KQmo%��#qY������y�������	�ya[���K��YL	���Eb'���`�I��#r)�O�:@�<����N�xUC��]���X�`�%�F��K�U�"��:Ep8�o-�I)cF�C
FS�zy��fP����u����go��x�����.��f���Z�sx�G
����a~���n���vWy�}p���c��� �[�Kd�l��������'��Y%���r� ��Z��������t��=�BsK��9�����P=��������2fA�R�7���wF���6�w]��!oA�-P�.��
�c���`���u):����/G[wY��1����A?�#LN�i�����a��#��(R%��.H��w��2��!e��S#��|C�8���
TF������T��J�<���E��z~~|~|&�[���P�(�"5+6��4�SV#j��t���L������!#,f�����}�.�I*�Mh? N'�S�l8���1��y:Y�����S�kz��nZ<�M�����������
K�4NK�(f(:^9�m�c�8��H�U�Ik��L5��v�L�-u��:�Mr�QA��,��E�,J�t}��*�0����'����e���,�N����+r��Fe��V��P��3iU0�J�dZozr���t����cZ�Mz8��^����u#�����$��D�J��Ns��d�B���f�AP%N{*s���J92�/���a�IW��!#r��\&��GE��f����e�LLC������A��@�OH�[:�� ��a.����m,������Rq�]
�nR��<�em��j�T���GE�����?�_�4�u��v�s]E<��(>������g��40�!&I}�D�U<���*5R<LjKD-H�|i`��kHG��v����h�N��k�*9.��!��G�`+�B��r�UJ�4���h�XcQ��.d���;
�V���i�>���D�_��q���k���3	��K����Cf��F[�,�-��r��=0�������(�Z�������y$��h(%H�������N��v�ah��{�D�\��].�+V�Y���F���%�AK#-�L��Q?	�B9[z��T���%�����z����@
�V ���e�hH�1H-�4B����u���{��������P�����������O�^����C-��+l
�dS��:�V�Z��cu�G�V��5��rj`����N��W2|b;�W�b�+}�y��O�{��C�*D��Q�	�U�%"��v��,h��S��5�PPW��l���i�,�U���<qs\5�C�2n8z�<�q"����D*��#�v)�����,���G�N����|t7�����b~Y"h���:%�@���R�(�#@>Ka�47�U��h�?���m�\]��XT�:������Ms^B�/x0#��m�0�Z��y8(A�K�r�bu���t*g+l������\�R����?<��c�UZ�����O�FO��N7('�d���n�8f��Ik�����K������<��`D*d��dP��A�z��vP�gN��k�n������0��$VPr�vIc ��������1+�lz����M\Q~5�?�u�����j-8����1���
�{�}���#�IQ��)5Q�g���L����4���j�5�6T	�����j9�p��WAI%K`Mh��I�-{��_����s��D��p/��2;3P"�Yb�)RK�g�!����E��}�T��:**�r���5k�t��1��}!
���Wk2�n*�M�7��s8�A�G
r��Z���8���A���<����p�>]�Rd��2�>y2�������94�eDK���er�S_C��n�6r�k����[SE-(�h��X(-��vh������s:�
7k8�%�����?����P�vPP�5`d�6O�z�|7����(Z�����M)����\H_O�]KE�Z@*���nKM�����!����d3�/�����Z~�K�O5���Bt_�p��=�F
@O
p&���M���N����a|�T� ~��I>#<])Ih�\�m��/�v;���^��P�;��%�dP�jmW_�����.����R
��:�����0
	�7���4#O����K�GV7��#i�B�[e��x/2�z��Sa���� '�_-�����j�� �4�_	�����0W�H���e���S�,�e��4'�nR�����
G��Wau���1�!
e �������Y)�r�����K���d0�t��]�.��-C�r��Cw	��4q��������8b�\T2Y7pC��I��������s��9���A���L?��(2����Yg*[3��1eV��j���:��	#�4�W��q��%��}�|�'Ko^�d
"'�
�����+KT}���1�l�+�'����a'}_�����1��}���(^s@qMd��r�Uz�W�,��O�I�nEI7y���������jR��(k!(p�,)@f9U}��+���N��
�S��-OH���4� ����ba=t3)AX�M��'{�r��UL�Zh���@F&1��i8�\��f�����#�NzlD��yq���H�0U���<�6-�2.����������AA�d�aL!��[#� 
����;|��Y�6�������������?���>�}&7y:�Xd�x���O�x�N���a-�<��|F�M��N��?���9�d(g�!<�����8�k�u-� ��c\�S�����p&�8�����d9�����g�)�b�N����n	�[��o�
D�B$[�54m�}#h���!�,��o64�	��/t���������x�5�����_��:��rg�aN���w�)�V��R��D>��G��C���s{���&ihP�����P���T��&�(��[o�
���5��rCz��FTl�w���
w�|H�.���$��fG�-L��#����:��s�d+�w��`2�)�z���
U��R�����/�f3����4'�s��Q�nHGZ#��i���SL���b����~����%�$CDAp�FGc,r��>���'�;BPu�$�m/�q��d���B�<3��������;����5B{���IF��L,D�,L���bjtV�I�{!���1����T�jjK<'T��L�w��
��,������!����E�u�C�M�:�u����aFS�mHTVgMjv��o@��)��&C�"l��"�c8�m��,F��d�nP�v�1G�lN�Pk�x�
��Q�=��D ���X8^A���T��u��#��}�{�M�+�X�Q�)�����l��?��"�B�����w�b�(�K1��@ya�^���w�W$����lg���'!u�]E�B��$T�@�JD�b�(x���kF�9��i���Y�Q�����=�u�^��g2��f����
�
�����K�^��@�f�P?������	
63S*�skt�Y�j�h�]�������2���2Tj�G��8*{[/��a�5C����O"�U~4��o�
�<(A��
a
'1":��s.� ���Sf���{hQ>	*P���\Y���N=�Qm(;�v�M*���M3����Q�^���H
�\�N^/�h�%�1;��W
��:��O��?I��l$��{��^���"�]��&���3�,�Q��U��
������K�bs�[����~��d��`��j,��L-I~G�m�H�������h��C�r�����7���>^�<Uz3�T#T[w��������]�P�	j��e
$6U�Z�.g�U����1��Ef����l��m��~ca���I�Q��i�����>;<,�BG�`�wtCn��#����2��n�
���`�����t>��=�ODqC�<ANt3E�]$���uV�J�Z��n!��k�\#^�4q��������A0f;�[�@�����,�@A��k���1LM�e��Z�.K'��t��n�{(�a��v��y�~+2�*c�E��O��$������.��~[����>�!�*	5���o�8�o5�Z�:9NM�Vu��+C�b�� �_�����!�����5�KZ�R(�P�LVw������	�fpjwc3�������[��G"���>�����C��0�EO�Q�$��aj�!u(��2���!�e�>�AM��b@�_]mo�A�8�����;"Ue;���������������j��f�hI'�_
�!8`n;��,�Q�3�@}�&+��=L9����.�!��2�{���oB:���N<�u�:y�30�^5[��A� >���k���2 �Im*�]���������E���$VN�c�����^��!Z��4p�>�y:��V��:��������a���	-%.������{��8v�o�_�h=<}P����T�V�p�|�v��_���C��
����R��6�K����Z=��J�#�G�o0�	=i �s�1����hrg����><gQ������ryJ���>�[��w����V�O�3��CI*b���c���"0����c��sp�^<�p94��n���fCr/D#h��u�a�*@�
d�j?^�*�^��9��f2���ItL*���������KXa�&dZ�
�����9���]�$k������`G�"�Ex�C)����qrH�l$	�t������o����2��������^Kc��{���I�=�t���������hT���q"�m��+���5��?
��@��f��J^�&�Q!^��[)�)����)��<cN��4���Y��0<MD��w��=Y-�7��f��E+�Q�hV���V�:��!D8���?��4c�����F���v3��NG��1�����������n�HY�H���IZ"��6���L.�A���x�~U1�rx!�`�!Z,��L�����
�s���2������M�r�� =`���P�yN2\7����/>��/�a���*�+;�N'3��X'��w��2��cQ8��XJ$#H	��v:�S���Fz��hrH�`���y��8B]�ySG������#k��EP�2I�h����a��7�f����S�,b���~e������y���	���
2X3J'��N^	�a����
�����d `�f�f�a#op1b�S��>M����������}��Y�����������\��H7����xf[���]�D2��0�0�WV^]N
�H9���r������-_�A��
&Z��	�Rd]O�������.f��M?^�Mv���$�kB���6*F�A��<e-B��f�������o[�/Z~���%d]e^�n���2'������9�B�(p��Y3
gk��b�oI$���G��}����%
� ���r����\��z��A�X^ULQ|]8s3H�i����"���;H��}&8��~�|
{��T.5HA��H��6�@�C� ��/M��%��V�G��u�AX��T�k3a�5�D��	��d��Z��ZT�C���"Y�������@�h��}*�p�+w��)�1��6�f+�;�������l�Z="�D�D���^ �+�xKK��C	�	3�0+��L�@1���!���Sp�nGp��0Z�k5jvB,'����IG��b��5�UE�M�4��AV*FP0��W���\��������h�1 �l1u��4G��*e���M���D���)�����[�!��&%D0�Z���5���v���<�-�����0�h����b���1�HA���jST�\*�#/HU����}o�N�D���p��/�b�5�E]w�<�D�:�C�0��u�6)�M�>����bY
�d��hB��-S�5�����N��]�@�l���x�l�,�yG�C���6�(�:����C�	�8����L�m��I����Q���:>F�}�q[:�/
�D��U�'��1�����.���rPp�����1���`�a��T(�sF�P��0�I���C?��=����LkR�����Y�F�T�V�8[{��Pa�m�,1*4����}d[>�	���%��8-���#B}������b������<V90��a�H*�	2j�v�$n�RB�sh�<m�t�yk4u�5
�.��@v��qA��Nc�-g����Y�������po����0
�m F��t
���#��i�����-���s\%�k�;��~����0:NH������!#�B*�o.�n�3/�SM�8�K�j.y�[T�
�8���y*��G��|�`D���S����"��=y9��2������D��A>��&c��������2�oi/;�!�g�,MT��-��|�0�'T��;�qr���.2��p���G���l���E38���}��:0����n����8((�U�#}�q@�������kn����D��Mj=#E�$��EE���@7�^�?��&K�����(��k�((�F8 �j��1_&	�72���O�QQm/T�y�"3���� �,3(\��"��G�Y���
�����<����}BC�����Y:~�]�iH����1�M�����JEa�����=Sa��?;�m�����f���Cz���NF�
9������C��Tw����� �������$V*�]�+u�U��>��wQ�Q�5}���Eq����]1x��9�o����bL0eI�k��}�T(?���2�������a�o4�%����2����6r�lI2���\/ �s@l�q���{"c@WD��6m/:*���!�a�2tA�W~�Q�"����3���=�bd�Xv3O\��D��}����g�Q"HX	��d*J�g�y�P��g�����`2d����T���Us�Fp���F:���'��=��Q��&�N�3�i��A�:��8��w�P1�S��hM�rU�|����]�5HT������B	I��?g�8Q�2���%?�����V����o��Ew�O��#B����t<�X�����Bx���t�H1 �����STy>���A"��gu��
u������e�`��9��w��d/��Y,#�C���_S!�s������}���D@'��0�Z��������_��0d}��1�����,\LT��J���@�����r��L*��>c��&C#N*u:"���#cL==J�?M�����T�<�C��	�K����;����[*}���yZG1�P,�?u�'�K�@b�=sC�������mdN��
���wd��	�������D(A�C*�[����
���@J���^�v��e}����B8INFr&��n53*�uT�*U!4#@�#`�
�d����9)�\MaT�1_<���V���)�[QB�1QeiG1�/������
�@��%�*R�<�Bm��xC��l}�""�z	�R�K��t*�������b�Jp<���� w�'�O ��B80��$���H]�OKA0�R��4�v+Z�S���z��q���'ukS�Z%�.�e���b+��=��W)C��q�����G��M��
�l�Y�I52�}=�^��B�{��e��G��?��Ha�+W������+7L��yd�N�����X�Z:uu�0��R����6����]�8�BF�S
��7B�Q��
��cCZ�
���HcS�5\%�����Dy�Y$Y�V$�
���S1��(*B�-)����J����$`U��7}u�F��
x�@�I%���/CD���|o
]�o�dT��������e�M�3����n�]�n����q����|(�m�r�(�I������@_�aSA�*(?�[��_����9�� %�/���MA%�+��e�X�@��c��?�j�����f&`�����:��Q�������� ����,���:�1�
�fG''<�;+{�����1 "����l"��o}���M�,���	W�V��h1v���i<�Q�<"R@���9N����C
��B�
�a�����gIO��
f�f*_O��*X�NR��~V��d�+0�������l�R�33������:���c�6F��m���~0���������y��L��^S1S/{,@�;�(*�<�Z��cML����]`6J�R�b���l��v��z����X
���;�������X����3Sm����`'�:���.p�O�)�b3������b�7�@����
����9[�j��������d�JsD>�������@�(��2}t����A��^V����{{4�k�p�a(���R���c�I�T7��T	��3��s;����n��
�G��C�@��R;.=���Nr#�����,�����������,��Ny�,���	!p����L�X��OisZ��cz���l����/�u�(��H������w��S�uZe�)Maza-�
Y�V� �����LQ��?���g)�5m����@I�����,.v+>�3B��I9�H�����X��*#������*H��w��:q-�f������t�X����qPt+��&��%k"�b���d3���j��j�U������0"���p��?p����a�o;���VYK�$F'��
�b(�Pff��~nUJ0���)��hT�x�y���
������Do
+���w^�$�m���J��R]n�d�9��!���EEs�;����~�G����a�����/�%1<�+H(����n8�[Y��'HF�}������%�O���aoK�./.��6�rJ�&����(Z�O���D���!t�<)"����V+�U�Y��*�D�z����W�{�����KL���$8�T
���QQ��^��y+
L���Z�[wX�C��kE(�o{s>o<B�����B��u�E����K\K����
���� ��r�0�60�r+���4�%N$BUh� �wH�p���|��m+��ZXJ�D���1��M}���q���"������W��:�������"��iE��~�R`<��80Xk��
#W0�
�X^�0�Y	���sJE
���Y$�l�*#1i,����5�#
�����I���.�?�~�LS��n�a��
�!#Q�u?D(+d��N��Y���Yw����/�O,9��!?���:���8����L���D��.rcC�s{�a����v�� *���8�,�-���!QmR�dL:s`��N�2B��� �����P�������4��D ����mN�@��O���8aO�``����b�:KE*D����
"@Q]�n���b�?��hl�Vh��4|�zC���r��{b���"t8\{w�(���1V�O�zkQ����r��A��LUG���mhh6����� E,5����hK|�� �(:F����;
��.���Qen�4z|�#/.>���9�"�nKb�\+���t�K�apZ%�1�����9����9:~���Y1'��xz���Ze���B?:�>F[�9WU#���gVA�4�I���:��b�.�^w����m��(�"[�r�<�8� i����8a1�A(�i��R�q�W>�r#�Y�m3,��f���k��Y��P���wQ��0�rP��q��r����2��$��[���m*\<�j����#&3R����t���;�y��^�4�/G�"�E��l\zIUo��G'=����U�C�`$	$�����BfjPa�Y���yI�p�R\4G�z�������6ul{���0����t��,��!�M;d?U�
�/N�4g�Q!f&����&�5wDxaA?*��E�������v����G�6�.4�CLp(;��FDFq7Q!�!���,��1$���E�1�E+e�����f�@3� ��o6i^*m���Z$c��+W����`Q� �\��t������0]:*��h�#���}�T�~@���.s�[rQ���a����p��89�p�md�=�`�$"�k9���`�'�"�C9�l��)���c��?�	'�N\���Ue���D�r_x�.��`nbD�&g��N	X�d3�����6)����j:�p�or�35U�	-�y��-i3�X0BK��B�\�^C�T��6�1	A�G<�^Q�9�g�P#��;��s����G�������
���7�������!CO���+����K`�3��$vns��a�3�-{L���F�����p���nV2���$\]���[�b�� ~=4:����2�tlk��PYhr3�Er��P!�4���U�e��Q���D*�O���a����
M���
H�l$&���d'1DQ�5�������
7��S�=��Z���%�8Kc+�@����O�H*�����<�HCX�]�7���R�%�G�S\*pg�z���$��k���h��!��X-R.B@SS����}O���5�}M����c�+��(d�v(�)V�W��c&��E
���tx��baP���������O��,9��^�-�+��2X9���P�r,y��
@{��k�g���1O?D ���� ����*@�����9H���X�l2�n(T$,����$�Ap-�Q|�}����O�i���C�]{�-���?���+3����	Y9v��1��F.�4��8C�M��G��� ��*.�m"'#��O(PD���@�����!�!0�F�G��qOS�����6:2�L,8�W�$*q������h�����4��B��a$�|��
y��$%X$e6�tbL�
���X���������c�/1����A�^'�w���zF�k!1�������f��\��/�!d��5!F���y8e�X�L��q����C'�&t|��h0���)���5.F��hjTLh��@�4�����I�PQ��q_��*�b�T��9��DY��}������`64����t0	����7�kG@�E�x��n����oF��`����C�+;�H,d[��/u������Tw�$�!iL^��mD�)pu���������6d0'A��GP�Nw*�T���Ti���R9�#;�98�<��J������@����:!HW�*a��vy�z_���HEs�0^�=�r�	�!���_w!0���~�t�zk�&9��Ue�*N@5���&!���f&�z����*����@$�)+$���*����� �(2���3qT��D�b<e%��{Dm
�5�kd \+����j����W����CV�����@m{+�L�	9pT  b�3�YY+�d�y����3Y�Qe���_�P�z��S!�
tm��^�H`.3�c0��E��6�bKo-���`�y���h���6�p#^���M���!�����@�� �Q}�^���`A����u�fv�c
�g?�F#����r��~p:B�'�X�������mt@i��)�8����_	��������A��QGZ�oG��Dp�O��1)oN����fx&��Q�S��j`��~(R�~�����l��8@�\1Hk�B��c�:�z,C�	��hN�Y�4�����XiQ:�&�q�S,�7!�N-Y8�t���`�z���zi��y
B���=
��V�����A��i�M10|uF��=�J�4t����%�[����R��j���#i�m�x���`��e��`�-'�Yi(��<!8���b<���.Wg7G�t����q��:���R'!Whf��{:FH&��d�=���&��mX���_=Y��G#�AOq++O^|U`��
�(�H�A�,��w��<K��T���"�i�y�#���,�I{M�J+�:*o��p� �J���wu=�p��#���z`�],$^*��;^��ee$Y0�����Sc�	S��T��� X_���p�"��>1��V���Ngh�h{�?>��t�0��Tv���6Z����*�9��K���N�����	��cR�sXT��"���JO�]X�'dR����dKu�*����s�/��{4����6�(���97c6&�������X��\�����9qjq�AR	\������ 4-w70�F�|t�&K� <����G]�)���=LP��1�{�po����Ta!\�X�B������j�����n�>B����N���
K�+Cyj��|V��*z!R�<���<�R��1�A��Q!�,O:C`��&R��
��v�����V$��X�������F�R���OKqN��eb�&Q�/��G�{82��/���0��#�8�N����r-]�rd�ir�<,�^��L-�Z7��(Z�~)�k!)��(�<�m����z��=�u�����Se%�Qq�L�GbQ�5G*CL�a���.�TtE�C�(G��Hz�:*i~I���l�@u�FV�S(u�������t������e�]T�k�^�Q�]����5�)R���T����0��eY���B���IQ�����f^����A�f�x�{�@���^^���}��IT�����������%ak(���#\�%�|h��?�9\��
_��B����s���"��opH��c�C,E���S�zu:e�~V��,7��������5U��Mb�{
��}SO��a�x�?e$�+P_�NJS������uhKm�K��4m� 6 �Vm���cZ��\A���t�C7A�������ABk�e:�������0+V�v�lz�,��z=mx����HP�@��2"H sA����q��S�g`TW�Y2��
�@� p�2���T�E��x/�(�vFQnA���	S\�l��/	����Q�v3��K\aa�����b��%*�!�G���Wn���8:�5��\�`7�B]��l��������8���� |�Ec2��p;����Jo4/�U�
NS�7��]_^�t�����HW����d#
��'
&��ru3�F����rv�)�4��04�����W����s�O���`#\;�J)=
�t�F�}��[����5<ID��R����!��@N���{�[
����s����7��o�R�K?�XU�!���$t7�H�/�Y�W��O�,�����N��(��j���w���lv������L�g�V���������'C��'�lC6JW
$Pw:��*�,���X������i����=�n�k��j���A�s��-��y�rG|������\�\@c�9�:h6#0�#~K<C 4�
Lg��gT����f8��w�V�
����Z �P ��� f.��4�]Z�\��7<:+�����7Pj�P_�����_{��P���d����T�su'�%����{9F��:���>�a��[-EY�B%M+�h_%��=�B���OJ	}G�i��E��d0E�{���G�v������^���|�'�37���x�d������+�P(�_��O�9f�p.�p��D���H�����p��)��8�i�Q],�����8D2D���Bw3Q<�cK���>l��p0����$�\��t�����.Z��$�v������2�C&���u&�>����r-b��m7%��}C�(�z�Z%��8`�3���l��e0�v� s/�N���cY���m%�rU��7�M�*���wH'4���mK#f&@�]�%��ck��@a�	�P	�L��jr���������&���i�T�6< "�@6#&�]��d�?&~�}���a���00@)�/�@��2�H��kecs@��.`�C6R0�����9�����!F��Wc�[
� ��j_�!=���>R�� �]����~����4��2�u�^�p��X9@2�[+�q��*O�Q
�4�wik��(����@ �,�0�i={�~��K�	d��Q�?�����2�H���nO)Q��5v�(�e(4um1G	�����D8:���vJ���to[l*��u��nT$��=:Q��P�&��<P,����qe�CE������Y�Y�[m���d�Bw��o��j�>+���0"��=�9|1�cH
d�v�Cm/��Q��n<�X�
����w�{xe���fo;A�@�=q�_n���BD�� �`C�`RG��B,$"������ j����~�M����fM��^��[�3n�Z��d��B1u��������r�V�c}���a;���T�������_��Aq�	0k�x��gM��5��A��9@7I��d�N���I4����'CK�S�P�H�` ����!��$A92�r��-�I�������g�_&7������u�[2��^�������P �2*�����`���.^I�-oD�P�F��������y��p�B ��J��Z�n^w�	�a��at-~�0�jK��.��"j�)Xc�0��O����r���V?��0i��=�._w��s�� �V?�4	f����]*����X�O&!V]�cz��f�kL�NS!��WN�Q���������N��c��83�2�������X�Q�=��@C��K!\��~��@V��(������B\��C�=Z`V�1��)�TH�?����z�0B�F*L���H��>2C����1
o�r�
_���1u<��b[���gH���=b�gpnH9�QB�0�P������
��s�$��a��%���>�R's��0u:�xS�,oE;�����mD��T+Z�,��W~���������Q��J"���3�����k)�~�84�����������4eq(�ru������~��\������C�������M���>���-��Y?hs���j���R! ��.6h�H�j:%�#m�T���� �yG�EK��I���9�:���jcc�s���'4�|W�2��x�,d$�='c~K��:��0���$[k�����*���������������_������_���<?�G2�Hi���_�o�O����?��rU���j���Ow�^������O�����/T�j������Ut����oE6���>���_
����/���������z2��������:��10�c�|��������������3��������+����j�rA�c���p�]��q�O��Z�]�Y����^`~'Z�p�]���$}��>?L�yZ�m#Zi'����?0�wF�:���E$#��I�$�a�Y�X��Bt$\�_�5U���~�^����s�
��]���a���T��^��\?�`}~��n����������w��C�����vu�����F�zu)���?�% F�?����;�U���V���_�~����:��m~���7��O���P����C�?���~�����G;}9���K^&e��=�0�����P_@I���2��?}���Y!���'����
>��/�g���o?������������__^���=�����������/��/��������������n�?;��9�(yz)s������������/�����_���-�Y�����x.pS�q�MZ���t�B��/?�������C�T_�������k�g��>��;�'�������\L�e�Ys��p1��	������{EM��KK����=x���
[��� ��/�O�B_|�����r������(w?~�����(/�;	��+��BybQ�\(��/e}���(��~|�B��~z��CY����w(T���,~�6�v�QF���y��~~|~�xl!����x���������k����h���^Jw1[�G��=����x�]�e��D�Psi�/����_��=��#Q����?KQf(��N���K!��]��g��n�Mv�e�]����x���w//�����D���������������/���t��?����"9������~�:�04iS���#����Pl�N���~|~ :��CY���~|�>QU��U�������H��������/�'q���O�A
u>�
���Ma#�
��P��h�����jT���ZY~��/�9WUt��I�x��
�o|���%]2W�����6z|�}��a��OL�0���'&�Eq�������yL�Z����!���9�I����_�/������}���}�
���g��t���p���7����H����p����nkG���=���Om��������G�Z@��+�����8{��_�6�1����R�G��>g�c2�s�:Id����]
�`}=�1�a]�axa7{�{N�G1�w�N�\d��_k�m����0�>�PT�=�`��������{��+�R����g�������W�;��rwL�[-���Q���U��A?�5v,�g=�Vx�7�����Z�3�.��>H��i�����wVs�����V�6�����bV�+�y��4��y^�--�k���\O�=�&0����X0������qr�x�#.���mu�X?���Ik�-������U_�5������>@r���qZV7�>\�������:p9e�jr�=�Xz8���/�e�{��3$�{10����V��Cg#3��k`k#�u��x!�U�b�����?J�	�~�j�<��B�&c%�$�h�+�[$�������'e^m0���p�j- ����z�U��U~��}���kr2�7)�\��$�����'��H:�qC����"�m�j[<1����Q|V&�a��}�z 7SO�}1�{r)�4����`�����������Z�����t�~|�|KsH��E������?6��rLm"V���5
�e��{~��]�0�4
�}rN�|���}�8�b=i�]z������ 
S��r�L��RQtL}���x���wM�Z���iV,���x���p.J��W� �z�L���Qs��{�n���k3���o��o�+�/Jyqp����*c�_fg�	���2���
�=!�w�sp�����/f�����m��
'&
�z�u�����	�>_D���\B�_��;���B���nk��-�a�b4��+�*�-���U������h=~�a(;�����K��%�������$���$���c-�����X8�	������C�m�sy�0�2�uu�1�=��\�N��Oe�S�r������+�u�����\O\�����;X[��\�y��mo/���#�EDU�(-`���N6J>�u�&���=�i�����^(.�Q���r!`�o*��	2�R��
M�fg�%�g�o�v���}X���Sg�?�7��R��E���F~��1�CE��\�1����o����"���$/��]~9�#�q��RhzJ�n�i��_]!�4��[���-������f����2�o��'����G���.�A���Ir�J������#�-�I#N�8��q
��@ x��0����{v>%y;�l���r�����L5�����2Co�Uv!�������9l�x�����(�Wp��&����[�j.�����x�Lx�'���7�T2����Re�X����T��y)�����%�op��z����S����T����6`�>|�UB1�{&c_���Y�����<�c���}����o���Ky@5���i�?BVO��2��R64S.�x��,������.o5�j�
{lpf[���<T�QY����<u������6v,s<���Qww|*�o���;����,��M_�iR�5�D��)��
(����v����Uc��ZMJ��B��#�L���Ar����H>6e���!�����6���6\>����ga|�.X	�>>E��[�
!;'3i�00���F�d�������-e��y[B��5S�<��T��H�E�u�L�+���NM��$c�`���������?��d���c:�
���w��������S[��|��XT�q"X�'�}����oQ����Yz�Reo��+w����T.���[���P�t3e��S��d��
���2�m��%������4El&����h��9�[�����Ek�S��<6�����^F<E�`g^�c�$���C����f��g���g7��<����5Qm�1<��
0��.��#)[-��Ax��o���?$.]2��T/�U�>��y���I
�a��:��ML&��|K�]Y�����`�0������:�
t�j����ecr6�|�Y���Y����{�e�R�]a��Ox{A�Dm�K���������<C���p�����]��Dq"�������nHV��~�����[wv��O8��M�3���J&�n'�H��E�����\��8���~�����s�&�Zu1��> 
R)sw;\7"��3U�!������,���>�3Xd�D�5}��c��G>��wG��CGBr��s1��`���f6�Q�uZ��Qd�_�u��T{}SE��A�g�t��2����pel�U�KZ��q���1e�m�[���a�G����k\�����h�<B�S\-�i3��wL��1���IB-9��������������Y��[�
��V%FM���7.��������.C��q�Fr������t �������|@���<��J�kI!���cf
��S��L����x���_�I������[�k[�n�[Id���rp��t6��5��1�������1j�_�/0k�^H�G��c��������[zJp���v��������$����C�{!>pw�w����upp����8m)�nR��������"�V]4�,���{N�:����w��������������"�)����c�Z��W�TY��/���g[C'�I~�4]_E�	�6�J{���LY����dR%{��u�k��d>��8�x���)Bs�����w��n�������
g�j,w���^P6I��~�����~Zh�ye���	����XD��������m�.��1���M	([(f�'����C�y��^3�O0.�I����u�Q �a<����9����/�EESm?fi������Xq����k��E��(X&;N1A�+�S�WE��N�5g���E���}����J��5������_�k�������v3�����H�FNC�3�����
y��f�������kw'x������^��\���Q��M��y
��]��&�T?����z������R{$9������+]t���{F���G��O3�����t0�K���a������
����U���p�6@���%���N�pmHj�����1������uYD�F������M���
��A�l��Z����8�����g_YDH�DE����w5��L�f����o/����Y�����^N~��o�.H�*s.��z��5w�8*F����);}���)7.�!��G/+�����a�� i�������`Z�-j���@�<�z1 �.�a���5W��z�V������Q�������
6V���<Sl�����:����!K�Uz��t���}��l����|a~Jny\J;��u������>������t8'�#�1C*���h�����+^��p������7������������0"~��S�v���S��p��E��aB��;&�t�	N�}���6n�u�����MyL=����/��/�Wh��tb�nb�X��g�Kg��/������:��-_6<M;�G��:W���|�;.��T1XY;������dkid��>���/#4�������I=�8UE��p
�I��[T��!�(q�5��9|F	��"53k]j>Dl��93�����|�2z��7@3u`V��=�-��s?���6���+b+��?Y-����ZX����N���������k��_���8Wf�	=u��(��tS2���&q���;6�����SC�Q�����&u�ef<�K�:vX��(��7FC�Ay+�^�	���:���������xA0.Jv���=�zu��+�b�M7���G;1���c���b�����1�:Yy[������22"�{��s"��hqLT��}�{�v�B\�47N��DY�* 6DYp?��-����5����zK�����$U8bka�g]����A�96J��bJ�����KG�G�������Y���Q�����
�\R����m_K�:<�#p}����:��$(�r�����j�!���k.��w0�p�':�.���U����4����p�EY�����������������".�e�����*���p/�N�K��h_7�$����o���F6hj����Y���o({��9/�F�ZpuZd��~.!I��8�w�?�{t����}����K����A����UUe�(E���Q.1Y��<���"	/����0K�6k�>�OD\XWt����^����B�!���D��kc�gea!�]�P��Zp���s �@"5�� 5.'�l�No&�������=��	���	��(H�'�t���`�E��M�p�{��:m���������)Q�:&ja�����q(�Bt���5|[�}w�-�x�~\��i-�VO�h�m���&�e?��&!�jt��[�����
�a���C�a bd_��z��:��d�w���)E,q)������Q{��q�
�s�MW��'U�,y�y�o����^�v�s�����Eo4%?�.����M�����Y���Q������LI�S�T�2WQ%����
^7snw�u���P��D���V
��u��..�D��B�0F��������)O#������{���_����e�;�����e����?����L-�����h�u
4�:j�:q�l8t�s[PjB�0/�����@�JJ����X����*�
���K~�mt�iqJLQ,�'9O�����q��k�y��ED�n��^�l�������Y-��m����j�=.�.A�O�S]�Aj"IR(u$ ;�*�xe��n���g���9����\D�6P�i��?_q)����r`�vT��N;��wap��Bo0/�e$F{�m ���M)�+���Lh'i;��e��\�����p�9��*J?����B���������T��K�n��$v���%�	T�rA�fq��������(��:��"�%���|y�v�>o�1��`���ZmLW�e]0����y��rw�b�=��K_���S.�c���p�^E�n�����^H�e�!��LB�s)����<��v�*�Oc���yk��e�$���P�U0P�tt������E��Ce�u8���iP��y:�������P"����.hK���a+3��(Je�z]�Il�#�[���o�mlx�-^�`��k6{��&��X�Y:\�������-$%�("�c2I�f:�L�A"�S'�[�U���*�4(Y���i:������tU
~���qNQys
���hoIx�=��&s������!lP;S�,	���r �gu����&�t�;�cU&]�^����H~(�e���N����^��=(���>5�g�������Sz��V��~@����K�o`N8b�l�Gs����������mem�`{N�XS���K-���<�:(�����(�|����r��@�&'���^Z�������Sv�������R���7�
.�=]-{�V�:$��:�$WX7�&�)�e�;��r}q�������e����l��tH�f1M��,��:���yJ� E�e3;�n�5�?�<.�����{�$.�6�~.�1��nR:Y	TV�c��?�����tM����������3���fQdw�v�:~-����T+|�.]]�r��R�&
�X�8����z-
`�g��]��;���BS����m��c<#d#vW�D�r^�2O��9E\���B!\��h�`]�z��������(M^z�����t�>���H��}`�"}�fw��@�x����[�%�M%�S�n�
Ns
O�>S�D��Z�u����-E��~�2y-�:.Q��,*:'g��Bb�����,H�CS���a)^vs����L��Ql�����^L�8+��$&8�(���'J	J�Y������U�.������@�r|1
��t�![7+������>l#&�����6�Sy��w��I����s%=-7�qf�������'��a�g�"1�p��gd��X��Ob�<��&k��F(�-m�K�wb�22�gxa���_k)�<=�������+G��&27��<����Vv(*y�u���%��������}L����^�����nP��{}�4�����\.�7��
-�Tl?�<B+����*���~�":��t,���`6�B�������8K�Pmz����������������4��������b�jV��
%o���Mg�-�*+$pM���:�YY��1��^�T]�{%�T�_��������3q|x<���m�ryig�N|���s�u:��fcg0
zY�1���9�C��je5��J�`KD��u����������vWrE��ozR7M-Hg�=.��Ii���OJGzs3��x�!��0
%�.0��e8�>�n�z���5�v��_�����.������a�T��J����������(�5?�GeC���������S�
�%�[y<�	d��?����^M���.���������-�������U(�r;8�v�
��7�v�g\���#��9� � 
e�8����$-w����w�"#1�<"5R��
���cQw�Es�"����P��xS.F����/���(�DT��E��TV�|�V�g����5��~�e�?�Q��>�r
�O�co��M�/u�7�d�D'�#���I/��s�DM��{(��1����D�*���`�QZ��������)������lc��f��a��OQ��OS�6
�Y5�|���pF���k�8b�h��}�]�Ywep;/1`���`P����D����+3}������,��<�z���n���v�}ct��,oU7�>�W%�a.��������i~I�,2��-����n]lNk�]�ud%*�1�%�2>����+��f(
��!��o<<�����*�9�U?Z�=��h�3e@�p��������0r��9�������.8���}���A���-�L@ns��Q��'�e����|����Gy*�����JH�m��4X��Fy������m�N��I�d����t���%������j�=�}6�p�����i�.e��){X#mH�1����4�~���[)���)�;���A��_1�ViF����CQPE�y��<�c����Qy���������Iz[N�5�~�h�<�������&�X[��}�v��s�u��H��/<���5X�D��#s@,s��+�%R�)�~k<�w��A���b�Y\��_m^?�%-��ft�����Ap�&cD�`��Ll�2���@�('8����p
�`X�CZ�s�k�Wg����/I	��[n��m]����Yye�F�r/�����~I�G��8m���<��q�����*���}�����+��g�$������Q0S�a�)�aQ��X��y����_�_����Mg��N�7V��sDE��m�TZ�pw�i2��C;�Yai�g�����:��o;��P��^�b#��92��C�b���t>���xZ�ud������9w����_��B�RQ�������\r@��KA���E����k������U�p���q����c:/P�������-Rr����.�;��]��c�(�9�7:�%��<�i�!U�8Iy�b��T��[^�r����������2�8��N��=�( �g��9I���a�xI���sW����7���7�p-���iUX��+���~�_��G�x��2$�Hi�R�M���6���L��g�Uni����:<y�$YF���[)4%��A��#��v%�@����{�#��M�������*f���V_\3+m�����P�����h���JJ���]��Fz��h� �"]����*.���."���Y��Ej���A>
�P���'�qlw3�_{U��_����=�T=���NA��z�S�����{�N�`A��/u��y8��x�v����`~E�����gH����z�f�s&Kp���
������^o�2�Oq����k3��&
�����5�.��I{����=�[�iw��Q��r_��z ���Q�=j$���1�z�he���N?�0P��[Q$�G�+�p>X��G���PD��4t���a~��9�����S�r�
K ��yj������.�+$�HmX6���y��?���i��Qq�6'sH���+���������4��'�x�f1��J,�n���r����aj�.�4]�N�yfi���6��nz ��B�S;F[�����iN�����(��t�����������d���mIm.�a����z||����=��l��x���u?������7���S���.F��-e�d#ku��:z�8e�o|�2u)2��&i�W��}�S���^���J��@Q�U������*��+n3���a��
��v�x�=9���~P�������'�_�����0��m������m���uK)�g�N4�
Z�4��>�n���N�kz#>�.oD�N�-�B�<?,W��:Q3���.��q���T�"#�������$I�����3����&yc),��������Q�O�c~�����^.�U�
fJ�@���;T36��D	Y��vT��d����yBW��L� ���yk�vM'3��p7}�c�Ed�Tq��� �����N���r����@�hB��,?!r���
��Yb����0�����S}���:�f�q���(K���K7SI�o*?E�9���=9L�����u���p��B	v��]�$Y�I`�w�h*�`�����=���W�[������������|Hwb���O��d�@��|��5?��y\R���q�y�[Yh�����
c�E���e���g����f2�vO�������r�n
���?>%h��cv�wP04�(�E��J'���	fe*S1��{�����VS9b��R��v�^�����C��j�a�c�L���_O��/���	6�,�p���dI2f1J
��4G����KJ`-��j<�I�_��
���0n����5��5�;�i\Z�g�t�e�wDin�����1'I�h!����U>�Q�x��5lp��������A�-��7�0����dMA��
(jDN��&3�=��vm�p'��!�
��$I�fn��:����+y��!��&���*J0�1C^a���U��y�\����u��}X�6�J�W�E����1O%�1D��GG�R^Qzy�
9n�P|���Y��[2m�~�C�v`����4�Nr��;�-���)=��|��oq����(����w���0aj0}T�:�?s�B�6^����-���b���q9�%�J�����$��C[�\��K�h�Q,��f�����'�!�*;D	4Q-_���]8�W�\,�x%�,���Vv�\�u��(O��6����3�I�P����!��ljf3E`*lY$��P�
���fU�P ���K`��N��Y����k�[#_���A�2f~(���a'�7�������3&EQO����Ov�X�GC��pN��
��>;�����V����	jE�C�,�Q�<�{�-'��eA��7�D�bJ�W���\���.�8���j
�����r��|�)����hLA#(pu�Q/�S���/�XTm�w��eF�"g;���(j3/�&L���{uwib�n��]�}V��l;��I6Lur~S�^S��J���k�tVEM����,5/n$m>�
�5�|��(����Mk2�$	���[��mf~%���F�� E�~�
D6��?uo�#9�]���+����p��X�����]����UoZo�������GD���{��N3��{���$$U*3�$i��������gh11�{t���(����w_�/��[&�]8���]H)�X#4$~�����������~b���a�������c���}�)������"R]9������<2��G�����*�]r
�]��x�<i�1W�����JI���BXdq��J%
;�S����`q5h���'s
q]���(������V��:u�*_
���|����1k..`�(��0�U9D��|���U��(����P&Y)�Uy`�~T�zPs�������;7�"�!g`�6��+F>�v�7aR�h�x*1�z�F�E��u��L��;�
b29#��+�d`KY{x�)��c��0��A8xa����!nO (��0�fa��O��h��Kc�n����3��Z����9����*N����,�����2�r{���Z�d`����T?�Bq��u4���a2 �?����C���~V�&	_��C|x|8��d��9DC2���������x�6���$�{���"p�D_����C������IpcZ�L����z�����@�z���{?dU�����OA����T����4J�����u�5gE�F
T�y��r��Fs�IS��8��qyr@.}��D>��>����D���?~>(V�6�v;�p�q(f�z��e��jt�,�������)N�Wt9��0W5&G*+TIxU_&B�4������S�"�g��]�IZ�����D}��J�i��9}`��o�3�H�R
�����QHz>
C�c�.%:,�y_/�Zig�+��@�*��vE��������Pk��VD6F�v=�����H�e��$�@h�l��E5.�B���^�y�`��pB��3a�YXu5������+�1��A�b�9�����d	�H=��+�(��$
	��w*��S>�'��u���C�P�����?���z�����sI��p�HA�w�
M-���m������&+����
��S��0�P���a����c��������H;�
\����u\�*^�Jn3�����l]��!3��[J�dKLG���Ane�����3��u�f%��Y�.OT�O+	e�v�vvXQ�t=6��t��YFN�
R�gI���E�sJ4VG7�E�f�/j�9l��3{���y�6z�H��lu�
�.�U��/5�H&�[���NG���ByE�3����#���q1��Kaa��0�����XK,V�PZ3�����~=�G�T�����c�?l��.��������S1�~XI!$|0�{9P�����p ���1b*���.%*�wh�u��%0������x�����Hi�����&r��2y!������T^�wn�he��lV�Jo�8�n~�����i��[��(����8�iI�����X������<���LT�����O����!R?1s�8H�HN�Pv�������18���:|t4]n�hK(
u��Rm��v���.��h-�,qH�z7�[V�#���T���������d�������6-����l��;.�x�NN��V7�W�zQ���.�2�UO���%�9(��~N���E��n���fhz���X�C5a�\�$O���������)���n��WQ�z?�U#��������s�E��q����b���b,^\YMe ��E�b?;x��g����uN,(�<7�9�f�O�r=�Dj-��Sl�2��
�j�����F7�[�[(m��94��a�-q/!���A2�,$��dh�j=�I/��I�j	�'���w�s�|yE�Q�]���S@����(�|��,(w�*����+��UR�2�������j����u���V���X��������p�A��yQ�#����m���d"`��q�C	��y�$�Y��T�VQ�&�k��y	�>;<�,�x6(:�k]���o��s�,a]M!�T
k�a�}w������
��X �\�L__;�$�E)��S�^�60���F��)6����v���T�[I/V����JX�,'��W�:�����Kys����uev,�E\��Vy��3A��I��>�+09�jR��]�'�@���|����l����A� Nt#�i�|
wJ�L���E	�����f(���d�@�r��!u�X��S�^@���K�/r����"���[�Fu�"��%��'�Ck��CB����t���^,�P��U
���Cc��<pD$F�,�ve\��c�bl��8��ZP�C@*��_�����U��A�U��_�&
��i&RR�t�N�/�Q��r�_o��hV(9GL�7���P(�j��U�scK��b�����2��C}RZ�Y���3�����
'��(�M���ubG���Y�}�z�t8�V+����t{�T6���z��k�����J�w+��f��~��,��4{0J��*�P��)�=�k}����T������IFf��KQ�T��
�8(hW�;��a�&��(Q����*��y�)�~���@�-�8���W(�T��
U,�R)H��b�R:��r ���+0����r7���=V�0�E)���m<@V���V��)��z��Y������������B��]��e��L5���0"���S�����������.5�G]��L�����!4j9�7��#�z��!�`Q�H�����%`�����X����8����7��mh�����>�/��u�g�����Zu��?�:>V��A�6��Ss�k�4]�K���I�����C ����r>��M7�RT�)�A��o?���G���H�������
�]F^���T���Q����D�n���{�W)���p��a�bY�����8�}�U��;�����+K��AF�����\����~<x�I�����z�|���"����]�����:!bU��u8���+��tC2��`����0��y6�?������� 8�����
���d��eK
nVG���
!�>l��zZj��[
����N�qO��}h���]~�Vj������?�#�|����h:������v����b0lN������,��Q��+9
�y������4Wy�����������m�:S�q�g�`�)��.W�'1��>^x���0��d��s�=�����\^� ����S\����,S� �����6�${x����0��������Y�?��7�����~@Y�k����9.7wu��m����st��s�������]Du)_���XM��,X�A����Z�j����$����!N��d�r��t�7�29 HDe9b8� N�8�(dVAt�F�bI�}R�������>���h5�
.��i^��A�[���E��������8��b�����>�?�
Tr��V��l�}�9��P�8�oNoye���s2��}~�����U�.V��w��3+��R�4����������kvjq0|s��ZR��``:N��gn�������L��y�����p���s���3�8>�c�����&K�+A=fw�JPI>Si�Ce��:s�����q�|����P���C�����������-���������8������K]��2x��;��u�?�r�*7i'��7�br�0n���� ���>��P����F��P���R*��17�|���8���y��&�3?>?����sr{���������+�}m��_���9�x8/w����|<$�uS�hL�9OM#�a�q��E�2��e��d���`0������:F��ir�X������(��s�@�Y2v���ePV}?oub���f
�"s}��"�������l����AP�'��M7����0�P���: �y=��9��+)hu�V���9���k�����+�E�������Q
DW��9���qg3n87��}�<k�C=m��K�
����y5�|��7�7[8��=�	��,��<b��
��8Z���h�s�Y����O=$&
��U�<[�.�sG�0Z�A9p��k��Q%��M��F��D�:��,{N7OO��+A=o���B�)d��I���	�k����8�7m�g����<x��B��#/g	����,	�3�_��*"�����=
eYm��s���}KNG5�#t����~��1S,�m���kmJ�q�~����]Q���).�_��Al�M���e�M��}�~���Q�����]�dc'�b@g��	D��>$�f�>���8���z|��S�&B���a%��4���Y$���%We	';3K�3���8JyY\�^�6��a����������{�;�m��4���1jM>{��0Q������[���U�f�g)���5����$������V,,�i���!]�phT��!���^�S�3!��� YB����v�",hK������_�l�]	Q���9C���jP�Z/�K��u�����3� 9o/�P������h�
���gq���?^Se�����2en�U����~7�J�~����f����T�����tHV�z����PZ�����x�]*9<oWz��q��z>�����/8Ae�O�������^0{��k=U�{x^*O����|���g�J���G���,�sP�.� �aK��Y�C@,�A�,��.K{1�?&�%���(�H;T�"��(U-��,�sM��Fgy��P�K���f��mLp��=���a�1�3��R�[�lv7�#��	:n)�x��x�Ghb���2����1W�!�������.�Z7����s���9H��G36MUb,����*��x������]���@A�|7�0?��T�pe=fy*���Qc
L�Pc�p��b�v:f��yy�:tC�����������fw�2!�NN>g#��Z�,�����*����b��lP�M�p[1t�
��b�K�4a8(N���o9���WP�o��rn���\��7�e�s�-`��2PV�[82���!Ng�*d����]k�iI���Z&���t�` '�V�������J`M/��x:7�k��g�yo�pwA��\��0�.s�A��U���k���d�
�p���^F������o�C���NS�����/�R6+���� ����Sv���������@����E|P�����&M1���(M�C��Q}�����4T��N���D����Q"t�Pd(���C�����)^A��$B��:}?t�����6d[d�m����%K�{�5���@������F��^��v�b��'Ja������w�]p��u
��I�<)�����	�-vY��Aq�fp��"�!`�~�.]M�R�t�M��p<S0����� &����}�^�H�`�a�GWA� �m#���0o�������*�$���8�Wf�LLu��X��z�;������������z���bUl���x1�����^+�=>bc��0��F������9����1�������#�^�Q\!��	���>��3\< ���o6 U�"���'I��u�@(J��a�
�x�O�9k���,y�������|�jKR�2�ye��A����]��>^5�y������]�>�p��� �c�,8������h���;�f���j�����k:�eS�<�[����s��C�n1y�H�)�3�@*�����`t�F�S�l9������{�NH,J�>Q{�-���u��r��������5��J�MV�^'0��5���9:)�vZM �$���mp������z�����7b`H������������x�|i�6d��[KGqVU�EA�����	�U&&x[�v���]i��oJT����0U�9��W�����`O�
r����#�7��&S������:��7��������.�&� �5���{�!!fA�<��S�Aa�U�����;�f3?g�9.�)x��%HFs��&�b�^>Qn=
�C��Gs���8/1Q�n�V3L��8��S��IC0�����X����{�i&��DP��)�'b|��y�?��j�sl�2-�2O�0���������f^&p��|�!|(?G$����A��Cr�u�I�}��c�?xt��oF�Q���gk����{�/���.����?��^`G�z1�%�(p��O��Y����`�B�E���m=��o��� ����|%c.2��D�h���@�6[8t���C�����2U7����GA��\�'<��������E�s�5k�TE�h��x+���;/�������L��V�L�Xc����� ������4�z��)���G������t�E����nt��A��TE1�b�[,}X����/�P�r��#}/��o��q�	i������Z�dh �rt�48hh����:

��,��e�6*� ����K``,7ApP��#�$�X6G�g��*�H�Q���/*\4����&�h>I�l6:�g����������g����A(��@�]�c'G��j��q����0���:�L{��A��=/�x��S����)�H��o��.���a�
2G&`�4e���+�X`+��c�W��X��Pq��-3R%.
TL(O$�:]2���]���8[�l��B�����,i���L��(���,3<p`H��$��6�W�����uRG�K�a���>5AS����ig�T���\?�=c���D���F�s�p����L���jR����7F
��<$�f+^����`���n������b��Y�A���\^U�%V�~��,=������H�WV��rr�u����j��*�R�!����Y9
�E���5��<���7����8��;��li��$X�!�QA�]�WQS���_`�	@��������!:��X@~-Xp�q1XjI80h�]�~�g�	B��o�������:\,8����n��,���U3���@��,��2����3�M��IuJ����Z�9hi��h�]���������y��f��� ���"8;@Xbm���@ltV���0<��M~z9�=������Fn��������|��t�%:����b.D�X(Kn#�-z�Ajj`K�XH��FY
N	uf��Q��F�
J�����E�k�5Y�p"~!��w0���a��Z�W�k�08�.r������=����|���BS3���,��,X?�n<@��<}���k2��[�����[��9��/�f7Lj#;�->��5n)�{��O���U������@1R���Q|��{p�����T�����V��O
�p���%� �`8�.�gr5i�y�3J'=�u"x�K$p�T]\45ce1�3?"dS(F�	M����-:^��_��&d�e�p���=x�^[�����u(���^G �RL���2�����4�}!>,<���i���{��"�?�Y��@����pX�Q���Z���N���Oka��������g��ce��Yjr�@�\k=��b+���P��+��t����j�2�3�0���W"l��9J9��\�F/@V���}�<^ch��/u�z1Z]�y�(W����0���ml�$�{����|�[�}�G&�)Dg.�tr���yv�M=�RzLa@��4i�;���b4������9�����/	F�?�>�p����|�/���s�1�6��������~=�'����z^m��;��M��v��*��4��P����Pk�`����1���zZ
��yW:T��!���Ok=U�����<yw:��y���|�*��t�����Js�����U���A�r���xO���_��@F�R�7���^�W���g�k�8��h��c$@��p�1�r,|��p���E���X>���o������	8�.4.�_��U��q����g����>����j���e�ud�
���L
M�SB�L�X�����!��7�&0���^,����"O��9~
��9,u�T:�P�R����u�C����~�J���)�������(<�W(i�02@6�5�����/��2��l$�4�6m�w��0�P���h��pT��!����I�������������8(@�;�b�b�a���8HY�ab<���%/��Y��Y@��"�TN��A�%z=D�ACP[}��!�f�EY�Q5�s�5�rc=��d�Sw:�h�����m�3t��,�����rXu �����c%<�\�bL����0.0�98H�5]cf73�S��AZ����h�Q5C��;��@�%�c�p�	O��Ij�����J�D�vO�������gr�XJ#����#����,���s�M6RgV#p ���x��Rw�a^��v5�!��\�c:Q��U���/f���`���x*�C����A�BX0��8�w�s`������C�O����������.B3��@���G��r�z���Q���@0�)���!1���|��P6(#M������EF���/kr�,����������8V�j2����(����6R�n~	`bYD���������p?��ze�������{�^�c��*�� ��'����O	��bV	"!�F!��n�oU�~�� �>8�/vb��{���cE�X�����Z�K���I�7��*�`T8�68/X��_<�L��u���nen��Q���N����-,�*����Z��Th����H��%��JT6J���>�z�0����>��P�s;1���X��iaK((���!�������;G�7K�j�JbBZ�S9j��-C��Q<�����7U*Gc���0�<#�@�5�sL�>'������
�j2�a�=��L���k�{��_�������r�e���K�&�Rx��h��h�pG�{���u�:�~�k�����"�<��e���s��O�/����Ni0c�'u`5>S�����	��_R0	��N��^g����l����������^����8w1>��u����s�:�~Tv���Q��������E���5����`j��<��B�R��o?)_���bV?yc^�����V�������-.���j���N{�_��K�,����s����/���7-����:�	�Io����r�#L�z������}�?��T��M���(����5�3s��3J�.��r��:������r�[]�?h���J��~���!�<n�����O���f]�o����@Z�����~j�?bJi����@��2������l��������M�-�'d@~�2d�����J&��.�E-�"`�}`a�=T����%L��W�#�I�f��}�8�W#+�C���#H&�M���/p��C[�p��$:�6S�O98 ���a:�,��x�
+�|�^9�2��$2F%m��n�:��!�Q)�B�YT�oQ��G_������� PL����wP��M�����L����R�:[W@iG4:�C���(�s��L@����&|W���)wb�����*��Ma���b���`MN�UP����X���u�`�Er���2��]l�����e�~���d�)��p����Y���Z"�c����P.'�h�0X{�a
l^M����}[@��H��8BBA�S��K!��
����@�/1��������@�(6���9L`��j�f0�>���w�
A���C� ������A8�p�{>�8g�R�����%;���I�+���_��}��?�� [��&�������d��%Nt����WC�<�z�=����eKc�=LLq�%7���\U��MNA(��$g9��LL���E������(�WG��X����Y�oH.���{���9�S������m�A��6}�U�, e��o4�r@�j+���T���-L	��]����������O�Eg]����8�O��k������d6�F��E������`-7orP�!�9�U�d'�`4d8w�����A,����5�#:[�9P	�����6nq�[�M�a 8�����%H�-lZ������1�o��A=�������b0i�����Mp���Z��}���;��8
(��^yH���<�+V�fP#���-='(��H��%j\�L eL���07�Xh`��%
t�s��5�W����"����
�2q��8?�9 xP���&(1������i8������� |��<�c0�j,�Xp�{[�0'
:>��,�3TB��Fs.�?�����ye�TL���a�����P"o3P8������j@[1�
�n4-*$X8��Y_�V5����1<����  �sk��1������a]n\�C;Y�������}|�cmfJ��/,4��4B��2���0#��B&J���#�K���b�"uYr���c�K	��i��O�m�����#��m�l�*�d�/�<��a1u`���u7�1�c4�3a�`�����k��M�w��i���D�j���6�P���H�0��k^��\E,m�B�J����|%F37F�����lN�~H�f�E%Y���a@:<Vs�F��e�`����������!�����m~8�vj������[��g�����{;4���|���}���F?��_����	�g��_�'�Di� �z{(��{\:A�O�,���wj:����J�	���\��a�~���<�4*�Og��b��)=������U�6����������E��>J�=�!T��~���?�����x���+e�����y�{O�����9^js�c�J�B���o�S����<���J���������T�'����<j�%��r�	����t����\b@��~������'_�y�_�����%���1��q~H<��
u�{�{^
�w�R��<���A�����P��n��P��'��L�:d���*K�l���6�JP�f��
jw��{�E[�P���� @��+�a�=P��
*��+���.�z.//�c~���'O��s�S��8}}�O������+�ux:�O��
�%���<A���Z/�o}�	��n�%
P���c��������_�����*J���-,����y�@���E9�����H�HX��t������C$���v~kr�����>i>�������>Y
*����������*�C(G6�#90i�9�.O!�`�kPS�E���5�4���X��`mA~r^���Z/�f��H�-F�%�`H�b��������a�������u���d^+�����������w���i���6�v����*��m9���EC���R��.3�R����Js���e�Y*�=?�kA���
�;}@���j������'�y��e_t�m��L4h�)� �.���4,G�Wat����S�[�_��k�>Z��~mF���|}�F�
���Y�����5��1�?Ld��J!Tk���f��-��\h��������@������k+�����\8��f�[g,��H���R8f��4��-�H:�x�R���n{�-i�o�h~Sf�<����z{���{#)+�:�h6�c��y~x����U��w��jA
�6O��z�C=ov��O�zzN�+A��������m�����D��l�E
��������0����a�|�������h)�a���+A�����gC%�.���|�4��N*�<�'�1��������y�I�6i�.P�<t1LP����q���}b�YPy�����x�q�V��1�>�Y�1\ �r.��c']��&hc����]y]mw��N;}L�Mtb���f(,�&S�����dz����6�n��-�T������*�lP6��8`�s�euD+hN�Pv��P�l*3A�����0��&Og��LK�,�b�_�����1<XP���� /�4�����^��Q~*P����L�F���Q'i[t���J���5M%�����N#3�
9Xp
����M��PEj�7=�r@��CJ�u*�f.���c$�����q�����s4�,
�?����S-��q����M��-0�:4��x]�����*�&��1�Z@Y}�_�2��l����b����q?���9{�?���<�J� ������;�'���h��+����\M�t�3���#���dY�|��o9X����<����*5-�Y��e���1 ��x�i�-9�[���}��OBRbh����B�0(��y��{n'�1�����y�DD����`4-������(_)"����a����
g���N�)r�����]��s�&��lq� ���)���(�0����`N��l(���B[��4�����:L���Q�'1��,m
�����I�G8������P�4��[��!�;��.�k�6��!���R�-0a��N��o�����(�,�?�����`�rP����D9��'��������|]#R��Q��1�k\�/;����`��r�j[����Q��H1[x1
����OJ��+|�:/8|	�i�t�hYB1�7����?��Y�"D�����G���� ��2�NY������m��8����==��9�
��.���[��]��>�f}�b����n�/����e&�P�w�jP��n=����]A%rxu����?e�:s������9<?��������Uu�M��+�J��������~w��IL�������}�����]��QP��JKt��p�/�N�VzA�����?g�Zs�%k����Yi���d��QP��N����y�uu����JP����S�w�~Sm��$����nW�[��E�����jMW�TSE
��F��	�,s*z���t���*+� �h��XSSC3��o��@�7S���A�����{8hN�g���Y4q��P �I�n��C���,s�&u��������~'$���~�����3
�������&��M�_�>i���F����W?�o���Z���P��5o_���/������a�����N����Y!�/_~h�*����~>�]�~�3vWM�^��|F�/��u����wK`�#�/����<>�{�=�f�����E}�g�)����_w��[��@,���wO��3l��a�@�����Y�4+i���]������0N�:S���0�gJk�a=\��C�}��������W�����c�e�����{R~V����vz�8��Q���������@��:�������
��L����E�Y���V����M������r��V�\��
o���n�Q��I���q#[���a5�*T�����N+��
���R����^4�6�Ol�f�w[R�.*C��X���7�]���+]7���-c����7��P����/��)����,�R�����s���������1����~�����)��I�6�S|��yv�S��5�]SNU�]����r/��u�E2N�-�!W���������d�+��c�IJ��
��F��Q���&����������r�����W�=|�v����3�j��%?�B�=��Y�s;
���us�-*�Y��C��\�L]6W�"�3����y�����#<,[
4���A��B���N�=������G��G�Y�uE������3������8A_�&��5����Q7����8�5_����4��k�9�`���D<zQ}�eb�7gs�����wXI�}M�!�
@�C���x��n�tej��9]�=�c���~/�OB L3�!���?^#7[�c����o���������9�P��U����4g8�\X�����0�����U�I5���W��:{�p�]L��.i?�
ry�����7���x�����v�2�
�E�m�	�������K����.��d�w�N;�-r�����+��`��JMV� ;G����"���3�&H}�	}�b����%7K��0���h�[���b�EFxV_Te�z#����A�T�V��7��)���n,:���fqW�GiV�o"4�B����0�u���zB�k��R����_A)���P�1<x�+�U*u��lg�pc�?\�B]��g�������cK$��/ZnP3�����SC���T�[r:Fi3B��/����~��vi;e�@�,|(2�p�����7jk����]F��n����~5�����1�A����<n�v�R��q��3�����|���M�7+��C4O�����Z�i��|��X���������|���z���5�d��i��l
Ypq��X���@��S�W@�A��:"6E��7�b~!�X�|����M��b�t��/��NW5��������{Rob�9�8&���5/6���������e7���\�����.���C����
p�c�^�������{	��^C������&(���0KL���rl�-�db��~#vh�����/��ktr��,��/���-��:���yD�g�xc���9(f���m�PE
E�)>��f�K�6���7R���wNQ��H�=��l���U;Spb�Z7Y��5/UR�n�@�S����������zK�%��Z�q[���W���n+]�p��`AU&����#N���f:')>3/iu���%w�@�E����E[o��XZ`oh`I��l��c��qy-���O^���Vh����J����ID��RG�u����'`��p%��N���T���M�!�F~p\:J����2kR+�Z��UOV�2��L6�SqXR�@����i��#��N���[�j���&����YkG��B~lP�O5���d�:��b�
`h�R�����wa��x�����b�"�#]������+Z@�m6�s����^�\���V�q�%�^X���!���Y�s���ea�����xKQ\F���g� ��0���no�Vzi_��&O[n��P�Ne�����
1X06E8P�aO\���A��	H����qWE��h���,�E�2��s��]�E�M������������=LwS!�>�������nX���P\���]��7�3eZY"�����7n�&X�EsGa��r�Z�!}%�����&���%
A)��:�q��K�Mni��<�E�P_��C���S��er+�����W}wi3����"�V��������"��1���t7@���Mx�|�pN����t����I��@����u���Pfs'�x�{�0��0��V�5v�����.^ i�Y�nle��rCX�=��zP�A��=�q/{�.-,,������f������[ *��m�����p��gI���E�3Y$^��Y�6���QLN�YZ�H^\���N�V-/��b�D�������n�k�AV3N���SG�Y�Y{{!��5�q�!�|��/�[3�D�A����cgme�G�3��7	y;Fj&��� ����}t9]�s��������uV
��g+z�����"P������4��J$v�f�:��~����Pm�!�q_1��B������JJ��YU��c0r���c�G��c=�o��_����?l��L0���T���y��f.�B}l2��H�
�dR�eOV��e.F��p��7�Q�Q�8�����AF�a �$�h��8z���_8�Q�m��m��U���0>2g���L��p��,5��e~�-�58��r�������z��sH�Ixi|��9Y���Q\������=�:��.��{7ofNL��pc-��f,��M!�3^�Zq3�	�1`��e��n-W��;��m$�E�Z��@?C�=��;Ld�g�/Z&c�o&�����Ru7e��BmQ����^r����*E�w3�G��s�E� Js^<�f��E�����L��+�����M-|��i�C�e?c���|��%��E���*������j�OA��!!�)������l�,5�r����o*b��U�=��o���h��]q��u��U�3�UV@zQ��z��K`�_4��d�;�������
P�c|����d
�uc�<����	Q�tl�m�'2�~�2���h��s�2����r�z	�������5�>�<^�y_7C��n�]Q��J��;O�"��@�;!���H�Z� �f��?�B�?�p�W����kV&���x�{v������q.��*O���s�����]`����
j����(����j���k���s�l��MR�y�����X"3�
�oqS�:��^��y���L���Ls���Cl�o�[��~{�=7�����qw����z�q����K������tk��:^�@����L�(�g=��c�O=d�����
�����a�3�I2��K �.��a�����iO�6��u�)z/K���h��R�">&���T �XKcY�{���/�v�$1�bgm�`�	�a�S��k�|s��$�#�}�6�%�����?�2H50]�V�yR��n�PY�F3d_������o=0����H����C�cy��}�|�(V���^��F2)�u!�����'��8�g�U��5'�a-�Q[�B:�g�Dt���y��)��0M��S9O��(�p'L�4�x�<TC���c��:i*��9��-P�������>��(%���-$��8�7��l-3����;��Y�>&=�f[����hY�"3}Yr��|�,{oB�`{D�)lyXb4d����
�1'^u����H,�n,C�MZ��6�R&���,M��,��
#��J���#2��������<w��h�A[��z1��A���&idv��1O���I��s�8��	�E*-�b���
W.+�c4��G��qY[\���������&P�m��R�G'wvom[`�	��O]�o���w'2���!�.����Md�����6�Y�����e�,�S\��T�*S��}&������a�1�S��L(MZ6Q���>�c��E���Z�n$l��	G��"v�=�@�=�]t�\,�>7�{��r���\!1��@�!�v�U-�N�������c/`/S�-R�&*u}:�U�?���������
n$H�+�����/��_3�B��WKH�78W���T�G���r�}�<Wt_�D�w��.��/q�x���������0���	�o��,j�h�iP!�����F����{=>�.T����p��������M��gG���$Q����Z��-o����*�m���$L���Kg<�6��~C=�u�����s���q,qH���n�X7��_�N�F��m���Gr��f'�0m$P}�uu!8^x��oam>g5�zZX��H����X>`uP9���Ir)��.�@f�'���=i^X��vM
a�Ffo��E�L����c~Y)WP[�f��
W\a��;F��T�$C�����
��aM��h���������/���p�s3�jVG����/K�T'�Q��_[������i��H��OGw<Y�p�|�S;��J��5t8�� ��`T�:�(}&��(�d�h���R� ����?�`(����1��Pr�U!�T�^�"�����7����s���;FN��a���XZAh�����:8��1C/e�$>Kt����X����O��������3�)�^�,]�f��s|��>G�Av��i���t-��.�Y���td��\Z�e]��}f���b������`�
e�-��*8&i��l���&����KZA�����[`+���85���������{j/��`@��p^#���T�r�����q���4��l��7�w���:Yp5�������^����6Xpp�h	r���S_@�/����[Ju���qdG����	��aQ�S���P��
�#����J�J���C=���jx.}e?y`h���A|��R�s�,C�Y�1���
���n������������n�|��zf1\�h}@���B{Q���^���<Fo�-p^L�2����&y���e��W�*.���M6����t6D45�!�nZ�H�b,�/po�2�KGY4�|sT�K�R�y����=���\�������(�:nu�w_ua���;Ts9J��v�Y��r�i����
j"^��{I����\-���R���U���yx0r9��M��9�����X�p~I5��������&In��-�M���r������H��k���&r�"/Y�E�{�fk��D�����T��4v�$�� ���X�Q5�G���u��qO�]Yu����pW,����8��hY��6H>J��
��MR�v�07]�n�.�LAt���3��t���O"�R5J}5�ci�# ��'C���Q~r6���� �5��*j�w���s���*/k�v��g)�����\��L������~�#����]��We��	FpH�2���)
��������������[�#�y��T(t�PH	�$
�����L����������z��I�L�N��JX�������=�������np�JYry0��������$s<��a��TFc2Y�
).���'5H�KThd'����lomA4���@k�����rN�`�����pY]|�^j0])Z���UD��"_��R������`�	��A���V�p
�������a�i���2�H"������w��s�n���u(*�%���.��XK�)�l�X�,���T��m'�$���&A�^/N���.q�X���~�8^Y�|��Qk�c���v>���T��������@O��	W�Y����}V�LW_�LU�����S;�0dU�k�t!���j�	JeCP2��MP�'/!K��3kB����L�HzUV�l���FR�n(�U�����B�l�iPg�/�m�4
�xW�XXC�j�
B�\�DSzk�N����hG��y��0X���!�����U����C7$��\��T�d�T�k�����0��D+�od6�����������J����;Q�Lq;6�M��ZT��gtr��S��Bzk��fFo��@"��������eL*���W.,>K�\�D���
l����s�Lg������sS��7�C��XE�������0�d���g
0c��%2w����-��>�G�G@���Te�������Kb�99����U��cB1�|��j�w��������"�a�8YW'.U4����d�W.����k}�m����k���k����)�W��Cf�I2�n�g��x�K���;9�w�f��r<U�-e�J�Y����/�zCI�P@�]2���:�D8��$��E�@�w(O��~�:�
vY�]��8�'�����N0N`��jh�-�i��!.�y�������re(o��Q<4U!+[�Ki�m�n^�������Q�RHk��M�	���2k���N��o��!k��2�p��}7�Ba��X �N��U���E��VdW�!A��^9����yJ�^|3vI&�}]t�8+����m���	��
}"R|�lnN,�5����4K�0��IO���T3����0rn��,�F#g/��N�������4B-$U��i�Ss���u��~�ECe2��?X�b�N����w�
�{|�g�+#c����7�C�4�0����9���7-$�i�
��S�o����K��Q�^F������l����$�d�t&!]�eAS�����R����n���|2�0�8�c���c�qe�d�n:Z������A]�,I�Q���7�R_C��*GQ�������4C���d�����z�e���������JS����Q�G'B�j��E��
���u*�qLF;-7��rYl����V�e����Q�O��`_5�_�d^�I<H��J���~]p���7�%���R�� @*5�NW��YG$����~�4
��PP{�L����7�*J��`q�����--���D��b~��<������z����&�8�����f�0\���������}�m9/� b��6<�AB�Qc�gV�d*+���2)*��2��q���Q�����@Z�w�Km^bt�y�)["�8��>��h��=#.���D
!e�d9����,��P�x�8�OKG={)o�!��Wx�TY����Z
�Xu��g<|3e���K�C���f�S��k��A�c8:��h:�%�����=0:A��H�e������s�������]��
�p�������:�>f��M�0�T�z������p�3�FL�-��3z��*���q��j�=�!�Dv*��I�pf�o��P�R���T��6�,�#��	m���%��.��P�K��D�b����.���:N�)�~4�������@���
)�q�%\C�i��SWb�'(������P6�T�~�F�|6B��{\�Z��%�{h�W�6��%��&�=��P�J�s���|����eb��,�E`��]���vQ��U����5��T_R��5��S��^v@�:���b���uH��o�X#��(����'K�BMz��:!�q�����c'��
6�f��U���f-a�����[q	c�|{�S�Q����=Y�������?��/����V�WQ�����S���|i�Y	aU��+�5ig�TC��r�zICv��:�e���wj�D�;�/��8/������S�#���`�
Db/V�q����2�@(G�?���di�����YF�j=,���������T��i��F�?�B�e^������-���`�,/<j���1��
_^�NJ/�]���5����+���������Z��(S��"�rO�@z'|��%�B"m�.6w���4O�O�y�����n��5��'y��<y��q�/>��ieQ�H���������k�bR���_@7
�	��	��*������v����.����'�"�]}���-�����F�����s
�7q
�C|E������{���|��R��������w�YeEY&"I���F^U�X5�pd��ae}"����'��#��`9���W����4�Xw~���1��\GrYW����}������.���� ���2"t���%�E�
��K�T�~��u
�P�����f�Mov�����4r�����I"{����K�!��u���kse�����t��X�����i�Z!mo���g��K�O���P>�b��)bkyE'�VjlF-z-ieM�����������\!)��'����0���F�I.P?��T� (�jO+�a�����&�\�S9��w&�e�f�h3.(%���c���A��V�K`F*���ox�*k��3x�Si~c�x<����YJNl���>�f�, ��N���F�;{����8>�W��-��������$�C����+e`�H�S�V�st����U�}���9��
�Lli	�\�{?dU������q)�
��SRQ���%����	�"e��M����@��X�t;(m���qzR.��:���9���/F��xU>~V@�A5b�G��z��jY6dRYWU=\j��)N�W4Ze�W��&19�!�X���*_2B�N8�A<9$�����9�
�f���hE}��#"����^���[�DRP�"���5������\������=|0����J�����&��Y�&��'f~'S��u�NJ�������q�*
��
>�� �[�G[�H��Y��V��J:�
��S�'~�*���MT�������YD?��ABo��jX�!x�3TC�J�9��Y�y)�l�L&��)���K���_��AS���N��� G]��\@��&��������L
���mHy��;+��,�t	�g�@b�)�r�w��)F�����(�U7p	���I
/�]b���3�gto����.����m�j|Z!��D����&Ku�b��2J���f	F�3�K��-xF���\`.�B�pM.�X�&��c1��7v���T�N*+��� ����KJux�
o)��+PHl]�?!�X���r!������*���6���{��_�����nK�������������'���*�����>T�����
���qec��"�8�YD�*���4V[{^���DE�D��Y.��PQ\��d+GXq{�/s*�s���8O�+:c�l��L
-A���zx:�����U���t���0P�n�S���X�u���e?Q��2������V�Q���K�e��-���s�������$
���fF��~���:q�����
�����A���A".3�&tRq��QjJ�GuN�������b
������|t�<��R�:�T�A�* ��� m4�����q��P���T������ZV���"\��&�����R�m	��@W�,����S�JQQ5������������Lm�@U��w��'�X���v�,o����8XP���n����4��Ce�����8$fM_qA��Z�@�`�w�@S��L$�E[:�t��Z��	�&y+��{�z�x�����R���l;l�u����+�� Pu2�[��y���G�x��*�c|#]i"����]PH�+V��]L��)�`0�3�o�X����5C)~WP��A9T��\zc�)KX�s��1�
9u.��:�ke��(HX}|���/�,
�>�&���V)������7[��h��]�C~$_	f`�rl�I��vM��,y���S���i���7������5��������]%)����]����nwK\4�53�����x�]�@}�R�����VEhi���\��d[f��c�u���-(���c����U�� �t`�����H)�m]H
�O-H?��G��2���zW�S�O#+��P$�5wz~S���s��,����-
[\6��nC�`<
�f�(e/PB<������F�*~7	eY�m6���2�Q�:�ja�9d:���q��`/pH�U�?���N�%57�xG��
\	�����p�c��e�$8�E���@���_&���'�sV�QT:��W�
�}gN�X��uuj�!���Q�no��f�5��\rT��R}2�h�mA�p��  ��m��A8O':�O�:���jl����f�aU�:�T��f(��I��������,�H��4<���C?�T��[m,�e��YA����m�I���GvA�f������*�D������;�{����S�7>�����!�,� TW�����a�qe���s���]�AE��(��>?�^�_���?S����W�Q�E�Z~*��[3�N��"��u<�����>T�i_���^N���g��n�|Q���f�I�Gw���Q��gT��F�Zr�`���J��STgH)0�S�D����K������J��I��\QO��D��]�KG*���:�1:(<�D:�������}
Tw5<�}�FK���tN���>MF���~�T�"��
*L�%cWh1��IU��<F�2����l^����e�B��i&p����� Fz3)��C��D��x��;���6� �R��B2��mR����	=XKO���9�����.::|;u�e�\�
����4�<��<5)����tT�6B�*�&���OM>q��;`R�v��T�=E���e��*{�}/�o���&��7�����^�t�0�z57�P�����l�.�e��
�r�����EQ�����:��%7hN���Z�Z����'����B,F��q��d[F]c��q�B����G�N�#*��&]sT���
�����_�U�j=����(����*��e�����
����q��(ZJ��b,\2����"���"�u����*�T�]y���[�
�L����
�"uE��(���Se�VYq�4oR<�*���a�@L����0������	<Rq`F�pU�"�
|���v�Z�$����#��UP�Z�5�����@���S���%PS+�V�IJ(Z��T��	JEp��4u���X����>�P��NEY\���?� C�
���qv�Q�c�t������hK{��X��#�yL������`���������L�>#j�W,T&����Bn.�Xb�/�<�h{~%x)��]��S�c�K�J
J�:�p���d|%p�l�4�e�����2A@.-$�!JP����GN��J'�������w���s���(�
��w��*�[��W���u*�R8�(>7s?*A��Ih�C�_&�!-���3�lT�DB��p�)�O����C�A�+�	�4+F�
��R�aI��4S�#`���MGG8�G��s@Q
�h�M��8�3�"������bH�N}<�k���s�*�$���(�Z�.E�t(y�;���h���� ����yj8*�y��o�����7�]���&@}|�� ��o�H�J{���C�HZh#P}[
��n��(.�(������l���64�GC����d���+�����4�L-�^�8@<��A����j�b)���	�)RF�A�(����-:���Y�X"hY��zV�oZ��yC%};��g
:c��b���|*��tRI�>� ����U����I�����\
.����[L
Vv�x8�v�1&�p)�.�$���F���I�N6L��Y�(���VH�x��dF��:,�Rv#0�����w!Y����k�mTtd�stR6��Z�:�L�N*=������4������KF0�p�C]A�����L��J-��~.�s�,��Q�7%��D�X��<
N�U�#��;�32��%�������������,��,��DG�����������Q�
4�[�.�������0�2��X��E(�d���w����������l.m.�\��P����M�������i�� ��CP�|}�X�n�P�c:(XL%:*�@����\)k��2\��?OD0���@w����%�2S���X��7���<$�Z��|�D�vL�G�N��n��AFN��v����w�M�O<O "���g���������
v������1�*�������v:8��b�=I�Vh6�
�%����D'L�a��+��J[9QV����nZ���������ru�jM�s������w�o���j [:���,�w��GOb{���U�o>A���k���A�x�}�w��4�������+��G��!�M�!�G�2!�;%Q���~Y��S����5U��0���Dp�@����9�]h�z�d�E�l��:�:~�T���]�O�r�����eM�2A?.��BA:�E$7],`��,t}!�O!O����v��` bh��_M���K��'�U8<���/���s����x��]���2ND(�V�XL��(�n$1���)&�_qB"��l<\��/G
(y���A�Yv�>1g��PW'�"�[@�#KB]��Y�!,7eR!H�� �����i 	���S���,���E8k�U���\^�W���u�7Dc������LEZ���HM5�j�
�/��zF�����v]�hg�C4B��$)�U����q�5�_����\��F,��z6K�_���@4_'K:��_"���:I�vH�P���e��>��gH}��&�V|=�M]�����Osd1��K+�P�����9H�� :	*X>�ida���j��g��]?g����}���U��P�p��<b��o
���q�0�Y�+$C��q)�CpT>U�������[�����������@��q	�]����r���
����[.��KUM�2���:�r_O�8S^���C����k�����/�T���	l!zBFXr��nrP*
��T1��q%Od�>��Rk��
_���:��hp9���H�0�������U���0���5:�S!���� >�E�����| ��B2����5�JL��I`�e@)��E]B�7�E4��.wQ7L||;��8�5X:)��A��K}��U&�������I*[K���y�>J��z�tY.��le���$��
����?n���4��1G�	M4�>�.i��
eg	f�2�$u���
�������r�Av����	^�W��7��@#�c_��h1�C�3�|��3�����F��Q� 9$<5AD�u�qS$�[�r��K�T���!�+�KGq�(� �P,u���!��l(Vs7������$����3bN�pma��F��X�c�M����D`��d�2b�.3�"��<��\�*���}:��h5�q&����R��"�T%��ZkLGqw��q&m>��I��&OE�Tm��3�J���@�aR�!�a��>_���*"kB+�J}x
��O&����N����>d(��F`c+��w�5�%�����j��B^"�$�&�� ������g K�^A�C6�(����l8��_�IUc=g��(x�����!O-�JT���7u�5��FA��+Kc�(�����������OI�Ga�%cA�����a�����LW�Y�JE�D��(�-u,E�e%*6�
x�@
'<E���C�]�5���M~�����Ou�3�,�^+;rz�d�N*�yX(��������/��W��
Zc���E9���Q�C�1cw1�d��uG���))�9�����<z����|^�L�D��m��-���\Q��=�b�9�R:�Y��*(� ��`Z������lu��>���rP�BU8�m��"�B<>�k]��59N�o�8Zfcx)�4K��OS��32���F�N����b1����@D���bb~6���[	����6���\9��"���,�)�C�����h�w��f.�VE�7��#�2�������2�e�:F��g��}�6��,�wP!P���`1�_*�C������EEX
P�;���v���{��f0=���
, ��em����	���AU����lI��:�S�5�<Gp�e��u�0�D�������u�)��3���g��� ����du��Hj�X�r��w���a9]*�K)u�����yO�X�D$����D��0��4*�2�!I��^m�����[���D*:�u�x����f���CMK-�=2���f����B*�U����z1YS��}�&�/cm�b_�4���C*�r����L��z	�fq/��;�+?,�)��,��$p���n����8����;�V��'��CVS��,�mHt M�J�n�=f`L%N�18���,72�1�
��AY�:�_H=;���gI�T��'d�(����6"#9���0�z�b��y^��5�0��d���) �.Bp��Tr��{q��
.��P���t��XM�ayE��
L�����Gi�|����w(�S1��������N��:��/T�:7�h/Z�sXd+B�?��a�b#����y���HUQW��.��>F��q�!�.;�q�d{�G��dA,�T�8�h3���<��GF�=Q� 0�.��Z���q��T:1����NQ!tm@�F�1���s�E���2��v^r���LO�@�(�ze<L�1N�$�l)�(j�d������sy������G��(t`@.�S���������
�.C
�:���E�� ��==�y[��Mv�~�S}��P�I��E�l����{c������t%&M��>Y&���[H4�t�4���]�;yzFr�
�6Z�+O�'4o1"�d��>]�^����kG�4H���5�|��0��D��H����cO�|���w����-�m O �6#H;�u��Z���!�]�i�9�� �a*����D�e�g>�)IE��a�]�vD�l���l-@f�T,{,u8R@fk��c��"��&��h��nPIS<��n}A*���>�.O
���I�O����h�,u.���']��&�e��������y��xZ�)��2 `�,�=�k��R���w���(�a�+j�,����TE��^F��>G��'�����|m(����'���e��M���RK��:�r�]J�d��9l�0���R5h/q
c���}rj@���0]Sa��_���e�F�~m���u��k�Jq9�u�jfD�8pz)�6��"�(�RaH�/��6�A(tG�����a;�V�.�WqQ�x;��\e��m����
6�cb��\$��b�r��EJQ�M��:�P\B���T$g:����E�m�.��qp�>��@-��)�2���~���������������?�4��}������Ue�����7�]��jV����?������y���S?��s�A���/?4p6~��?#���?~UW��G���)��~)����/�[��}�RO�OO_7��3�f������GF��R�����R5�s��w�������������nX%
��t�a{a0�%���M	�-s��0���qV5��Y��r��nu�����k�w�oi<5V��u����{����7�?4��D�Z\�Df����ri|�o���}j�j�[�Oqs�0�������E� �o�O�vi�+e���r-p��Y�,w���O��^��:v!�~zJ�L���W�z���w�ky-?����C�}j?�����������k^/���Cyq�����|�1����t�^�_~���� ����2�^�?@c�����uq���m���)����������{�����F��{�}���[��n��n{w���_�B�a�����Q��\���S?������__>����_�����r��2~�2�2\H_����K��u��__Z�����������@��K�Bn��_�A�[?)���-�����w�w����������jO"-gI
|���*��$M���������q��f���7�p��{t�����2�=�(��D��,���X��%�
�<XF�\����F���y�O�DE��_�P�}^.��)��E����+�����wl��P�;.����]�tE;Q�kG�,Tc��Fa(T'������� �JJ+<W��+��,��g9�K=|^�T�C�����D!�J�NB��e�2������#�I;~��������i����W�U�A�����',�l������f=���8��S�Y?�H�W_>�Ba�n��I�(Qn�e���h^|��"hV��%7Eh�(��"��3t��6�)�0�l�����~d���p�
l�NaC��������A�tYq�'�&�����m���X�������������b�{Va�g|e��T�j��<�������Z[����ra�ofg�k����8��P�;����C�P���[T@��m��~����	!�V����4�`������@�^�T�5$���--��E�{;'�=�����K��c[���m�x�w�����S?�y����x� ��%���M�`�5���$�W�1P^Z��Q����5��i��v������r
$X�7�9G��U��8j���+r�:Z���:�fu����U�{
4Nfu���p�|.�Ex���%�����������NV,������R�ma����2mKe��7�<��������o��������Tu����!�V�K/*�=��(�S���8,����4�['}�e&}����:��<=�8�-o��J6y35g��f7��Of���c^�C�����,+��vI��%����#���di��a���Y�/$�Q�.6v:%�uq�=�������������/�2���v�>�!�Z��A�C�{�H�MH��Ob��G�:�x�Q�7�)��_=W�G�S<fRy����(^H�����66�c�S@����X7>����A&��ms�?��Q5�����J&�o�G�87�3����#Wr\��2� @��������x8`�
�E�����U^E��L�j|�K'd;B����0�c����A�m����IAo��n9�*����
�Y67� I��5� �������d�?9�@���ce*��fv�/���K���8�A	]��h0�
�p?���|-�:M��
�LS�H��vA�#��h���t������v�x��<��6�������L9-Ah�E[6��d���`s��2oi�y�u����G�{��#9�\���+I�VM���B��0���i���{?\>2�� �����_���H�efN-p�-�5���S���8v�=���rz����(�6M/d��g���e��^�C�����c�H����K.�y���#�f��!�]|���k�$���:r���:�V����
�:vl��<Y����>P5U|�a2�.��2o TM��~g5$�����F�\J@��f���f�?3_���D�}�����.�/��(2{�:��95�-jF����&�ez�p0/E�#�����]z�#g�i���������`����G�����I�v���>���%��������$4.�4:���yU����&��T�����KUJ����N
�\�p�O���1��r<�%�b��~�������\���Z�w8���U����������>��)�!z������eH�7�g��a���!����>)����(|�)���iuP��6�I��.��0����=�=��2��7}��;�eo�I����������1�����&�=����pA��tgu$��>c������sQe�6u�����~���O�����Ox��R���_��b��������]�*j����p��T
�c��!����$+	��,'��Y��E��g��2�~-�������������^Lr�����fq��G�'2�����w�9e�����e7�@�W+u�}�������C�/��i�L����0�E=�,�8
}Mx���0
������wB�t���]51T�b����vE�k^�h5��g�e�W��g������'����T �����l$����2��'�2��)A����:!�S�U�U�b���S��I~���RW�{�1/v@��Hrsfo@
T����?tD�?���n���c��?�����n�<x����O���L�������0\�O�4�NzO�S��C=�a�\q)3#�Y�������?��_��?%�G��:�xGO�����\�������%0�9>���3������*�/��*�����J{��F�_���w!�������^tIO[L~Oy���.G���������aX���Q~�Y��C���w������guX��a�H�������j��h]��SDm���r	�/b�kQ�ff�xo�Kk0Y+���6U��X���vX:������e]���wS�K�Y���?�w�g�� #|�Z�Z�yN�:q��B��W+�04����4������a.����XX���;��>W�F��O0Gqf����>6s���7���������]>M��y���)�1��kf;k���~k��,��K�l�0�x�#��\W,v�'������������|���@�RV�;���3�8���Z=�mBqA�qmM�����Rw���!��X����9K�|�)3�R5yS����r*�hZ�������g	](tS�j�+/^���]�|{�l���/%Y�����n"���l�6^�!4W��tN�����-l�]
p9��o������h�X|N?]M�.;���l��X;��P*�q������GO6�����~F��!gCg�{��r���5��9�$m����5,����E��O�8�
O��/&=�/��T����"-���q���9�z0Q~���Z�E�#����#�}�.�)�����H���������+2�M^?A����[`��u�=�L/��C���U�J�x��Ob�,w�����C�u����lb�����\O�z*�oG�&qWZ:����������X�~b�-��%6������.��73���I�&9����u�D���SM2���*��B\E���{u��{]7����H$�W�s���www��2�L*��N����a+Nd���~����T�hZ����2Y��'3�"<Y��br�����^��B��/�`��!�4v�G�Bi,���T����2F�_�G���3�����}�5��(v�m�Z��<	#E��-���r��v�:������I�?�a�R��s�����4�����;y_��3czj�|�p6Y���������x�x��&D���s������P�4�d/��������=}+������Q���^%o��s��E}
E��}�Ui�.[=\?�@� ����e��&��OC������}�#�8 �]S�.B�fZ�s��? e��Tk���s�Jp���A��Av1�l������8z� Q�Hct�Z�G�	�;��A��m�Y/�x� Hxn�:=G�������-C�~>9�bU3R

��9%���$��b�Um�y�V6:{������"Q��q�%��[��
�0sXp���������X���u���<\3����4|(��9�U%S���"0���� {�����{9qv�BQ`TE`�0�/j�_F�p��C�	6��bi6v�yAt4�m��W�K��s��L��[�,`H<F�Xg�Y�VUi��U�9o�:���[)P04��Cj���X6��Zx���K�!��s�C6.}g�e�]�<���j��=��X]���u� �1PU�����m~=�r��Ke^����$"X?;d^��t
�@�D������j�c�/+�������i�~]g��;t�!�y0��Gn�6���g �]W>�s�����9�4X��A�����jb���(�J#�izny4�;�I}��`r��Sm���.�}l�1���-������-C}�W�d?�
k���)����G�1P�M1g��Q�qo��d���	���m�d�����U���K����ZT.)0:���_
�Y5�8���4��1F�������Wy��+l��_�V������A�c������5Hc>���S�a� ����*N�$���o�ab|=N:
/>@�X�&��
l�*$����3�o?qY��R�2tZ�J�H�QOq���4����6�H����w��kK�Q��]��@9�s��a�����!��6ut��<�K�QW����S����}J�S��f���5G^=�\<��Fe8*�}}%qN�������9��m7db��:���#BF/(������7��H�`�:7��0�����YO�DyzOSq���Q/����.�R�h��,/�I���%�s�������;'w�}<?�k����`C2q`��p��[��l0\F�U��Q��l_we���-929��kn��Mw�4�Z��j���H�r&��IJpG���?��X{"�������7���vY���&"$x�`����O$�Z�������O�#b<�9,q��:`��!�>����j��U�7��v0��b�5����[(}�'�tDL;xE�+�N�N�VN�Wh����F�h�c�����������h��bj�Qp��I��6��if���{EDb�$)s���Ff����������Ae�/�M?���
���jg�#Rmb���
2��q�/�:����TrYbu(�.�k���>���4i�V])�e����$��(:�n;���+k��Q��/ ]�W�S�Z��8��G�������uX"�JL�P`�z9d�3����8���E��9��S�rYl��Q-������dt��w��i;"B������<��kIs�(g�/����S�#6	�cD1���=9��]~&��W�7f���*��� i]�5W
`��hV���?wm�,�\��9�`�:�/h���Q'�������)��L��@

-P�+vU+���]D]���J�i�����r6���X:��cQ(�d%3j=`�����������S
w)I�����~>���7�+����uCTn�n[_J(6�}�FU���������_��8G�R[�����)i����|f���@�%"���t�3���')5A|1��'Y���1{���Oe���q���H5H��-��j��2�i������Ih}i�x��y��\^�����m����re����l������B��������E�[t'���r��"��2y���? ����Y��@_��I\� �����?y'��A���:N������C�t�C����Z0cm�p�������p��
�)��j]��
�6�6��b'�C�16��KS�Ax���y�D$���"�?��Bc^�t%��/�{$�R�P���y���� ��q@��m�H"���Q�
��a=�p�H��T���=�3��G��Q"��,�W�4�"X�/���EKN\�M�HJ���&U��I�r����������m����xn��Z��Rw���e}��?;f`i�*5�Z/�m���������/�����(�S�	�������
����w��u���y��2�����`�5�+Ag� w�����"8��v�#�&R]�%of����t0������u��y�mE7�����$0�K!�����������'���P���I�cl1�=�1-���D�d�!���J�BI�@7�k����Q�ux�g��gm�a�]y��������R����C�H��Y�Ol�L���n<+����X�${�'RG��p�������"Y������I����"6��B�Cq����Y:��N�P�����U��#�hApo2�n���&0��2�K��LL6L�������Q����W��dTn] \��:]����Z��������R�J���k�qq�q�k�g��B���[\�T�q�3E'��(-Q�I#~��p�M��W��Q�bJ�*�\�F�[S��XL�,���uF�_�Z�Q_���W����(������W&c��(� m������&�����z�Q�W���%�@ h�	��p����)�[����#B
��������o���y�n8�����k;uP��+sa����(�o�j�rGy��S-�^��^vw���)E3��'����/�b���R�����.��;d��8�`��P��J��L���A�f"�'i�'0i}�NJjq��tD�tX�Qz�o������=�J�����QtAR�����;���t���CLe���8|����P�QJ�977���Y�����yyz�%��p�f�8$���=T}�f��N�Y��a�B(K����N��x��i �0G�#bK�`1����#JyS�\H-�a���cd������X�Pb��p���*�Z�j�I��>��
�sQ������(��1m����W�4�Z�Hu�� ��A��G#���9Iv�Sct���>7�S�GB�R!�S�<{rD�`�>k���������B��Z��*��L���Lm0�L��C)�+Zi#�n�=����+��������������2@����R��[�u�q���^�+x�����8���~�Y�L���Kkh%z&��+��]�[x�T�9��O�c?�#,��]_��
Y0,]��@��r�i���Q|6����{R�gYIC����k)entv����'��9��D~KU90^��T�QFL��f1az2[�f����G	���IB������ll
�PhX��s��B�<�������6q24����(G�[��+�!��i�+Y�pN�4��M��%,*����rQu�9�a��H�(������������E�$��&
��~(WQ1�v�p���0��k���c�%�7����
E��6j�������a������(���$��W��uD@����;f��C�L�%Q5��������9�e*�x�J�k�m��#$��[�#,�����h��k����i��O76R�����Wc?��)� !b G���U�����Wmj�H�
�,;:�@����v��5��������_wi�(�@$���������]��ZV��a*����X[�,+���MHN79���yy��]�~��n�n����n��b��,�|E�1%'{����|]��;��pJ����/�u�����hV��a�
���L2���#�O��C������Y%2Y�H�F�����F*q������M�(���)�g"�����?��zMv����y���b�;'����T�Cs��p \;�)��z���3iE����dJ-��
#�2$�-
u��s/�K�oeE��JZe�c��
{��$(n�)[R{<�t�W[��u7�V1�
�{�s�"(�_y�������n�|5b������e���0j�����
=���_}|
���C���Xrf����aV��&B��K`��W�t�\J�K����E�R�I%�+LT��!�
�lkd�`�w��E'#)FH*�����o\t�Jh�x�58B��d3�?%�'��gL8`y����R��19F�;��Q{rrq���"'<ea7���than;�����6x4,K8,���S�0O���2�6&��`�:Y����#)��VO�Sj� �9������a�2�J�=�eWr�����De�I���}��`y��bA�dpA��BM�!F��+�-hJ�@DE��G��V��DO�q�5-m��4�u��_ ����������V�k�N�F`�T�������'�)_�6ym����`���T��Z�Rw��bbPt�T�Y�v!|�GQ����t#�y�u�v�i'����u^�1eyS�
�Ms '�4A��"��,r��6��r������V������% 0ml������O��.�D��"#n��j���r'����~h��Tey4������d1�����z��jA��L��=y�2
��
���%@��k��m4g����2����5��N�������S����S\	���L��oIt�H>&4w�"�
��RG���Q����A��s��#�%x��p�6mD>c�P�z��^}���o�[-pw���y���Aw8�2�t���!L��
2�'���M
�����r��&"�m���S���5������L�-��(SD)U�@��I_�I����'�����Y�@z�n8+F���5��0��J���+^��><�D�,r�bz��Q��?h��A\���T�t5*N�a����=3���f�A��}��rR�p��V^������ 
a�Zw�]78a��V��q	�|��(�����<�����xv.�m���=����N�
�Zc���r�X.m�5�80�Cf]E��N���8 X��"�g!�H�7�Q�0F���RV�������<f�	6��Epz����:�����!z��������=����=~�s:��9��uz��^6���
	�R��=\�Z��M~9���9~�c6v�r�U�!�z���@%���w�*>��oyZ�&�$~���c�����sg���v-�{Z�p%�O��	�H��)����y�@�M��#y
���	��/n�����f������_�D���rf�k:�z�t:?�������a��W���l��YuH�d\w���"�%�A�E���~;��x�(N{s��3�����(������T�?� ���o��p�T�(�&iB9�z��U/��x��r��:��������(dTN��u p�x1�X:q����H.f(���
�.x��H7���H����`\�hM#��n���������p0�q��#�.�X����0��iP���.��5��
��q��'}�z��8J�����j���sA3�V��Mk��[��r��Z#}��]��0P?������\1O!H����0�������<���6%�Q?G�s�gb�~7eAc���g����c��g@8O'�������I�5X=�s��n������B��YK;,Vffq�������4 �?�Fh����Q������{����R��N��E=+�G�y��� M��mSj�F����Pk}���K��gdc�@������a�����-0Tl�Lq��.�}>j��S�f�4Q_��������,��+v��L�[�n��D��F��i��0��v�Wjr�2'
��L���;�^ya��(�K����,5m?�����e�Ii����]_��(����L��x��pNm������T�C��tD��#jGS41�h�@j����
��h����-k���,����Q�(���	&"0��������H+ eQ�yO[J��O���������9�E<���t���'d=��t������t��q�Ib��b%�'�A���:��f�%��������,R���o�6��<����>'��� W�>���W�p���t{�X���@�����c�����]������SL_������$ce��W�]:F�/�����O������ '������T����e�5�����kW/!�L��G|�TG�T�O�;�����` ]�����]�\�j��w�SQ�������z��CV��*�.0�|�9�����d�'�{�:���k�!���U���,��eq���@4H�j��^�a��u�X���t]}C��(����B[����i�0��a6F�����|2m���EKKE%(��c��\)����-�S1n����PMI�#�1��{���]�a*K9]W��y7�X�4C[\���8DiU�>��5-�"��#8��c��.Zq!���:t��c�,���}h!9Ra��LH#`z��9�>�{[uV����������h�Dqi�|7����������(�eo��9G�f2	����qL5��nB�H��O�B�5U�E
�3�/9��0_��R;�@W��I2�5�3��]�	��j�� ��V�T�m+���f��e�������e���1K�a?�.�W�4M3��)�UZ_������JkD�����a A���O��<]�<��26���EHOK}�	�K/Q�A`�(_s����T����Y.�\����A�6�>���ja�)���b���O���v*8 �/LB 4id��W����}�U`s��7Gkn
��Q�F�$����4�f0��Md�uC��j�B=5�Y������e����}�~��}8�7[e��Z�F9ez-#����� �����P���L�{:v�Nv�h�Rv���Le
1��g`�����
�n*�B��
��C��ms�iE���K
��6b0��W��v�����3�I�����_��L��"��ie�|�IM��u-"C��H����7�~f�"�N�a����Y��%kCK�	P�i����D��E	\N�i`9�L��R�j�Z�l��"/�x������M�v�7���
D�u�E������(�w�[�*�����<@tR7�E����oUYV!�w��!n�L�&���W��U�f&��`L�LqV�"�?Uk�^A�Rk}4G4��y��u]K�����n�GD�����@DW
$kx�0��=��Bz�'�(]��=����E�r])J�7����m���X��1%�<(L�@�:�BG �:�0����9W�Xh��
{���X�;�i�9�8�2���=t��9������	�1Dx���6�#H�����i:����:j%�0���
�!��f����F�8`^��3lNq+�00�2���r��,�q�����&K���z����>��xN�8�����>��T�9h	A�v{�	���Jb���l��t�(����kR�n��)y�F@�V
�+Rr=�'-d�������sY>�k���M�����������$I�)�G����	��M ��<<����9MW�	.�S���������F��
�K�XI�:���)���'�C���e���\Dt��yt�6)�<����p��3;t4��A}!�ha��h���
f�(��'���+
�7�����E�S��P�O�hk���W��!������h�t,k��1\��N�(����8^����
���[�����q@�������.�������)
��|��������7�G���-����9:�\��@��c|w�^�k�::�w�1�	D��k��s<��Z=//��+�K�Hh1��oW�$'��{�}�(�/N�7�cye��������G�
���/�u9jz�S�$�q�����$�
|��5Cf�r����'!B�,N:�]?�9~�Q�G�:��S���|���6�T��O��u��C�U���T�A�<=����J:���9��uTA��k�)�tH��}Jk}�t��=V�Xl�D
����C3!����{-�����L:��z�u��>�������X�Q����C8���;���t8:�B�Tgdl��t8�)c*������*Ik�y��:���hS_2`�+����8�r�V�/���G�j
�T�:�� ���u+��*D�w�����UrR�x��h~�@�������==�6&(�Qp�1	+�q?�=e7��������@�7��s�SY�///y�{��d1��|w�Gc���[�!���d�1������d�� ��M\�6�Ci��?3L�����(d����%���)C�B����iv�������-�
u�������4�"{��������x����9M�*nW����\ilk��%�� Y��.y���$�le��%�c4J�8L�Ro!A�C��������a,��t�&�>�h���Yv�A�(f����}�D�o�_�}��A�W�x��t%zBX��7�7/����������V��H��mtiM:���X�7��[�~�O��Drm��������8z���Z�>���>r��~b5�����Q�q:��|�h�d`���0_7V�4�;n��B����GI��D��H��&\(-��Pf7��c�%P�R^o���q@O�K��^g�����/�=>�m�j�����F@���S���}�������9����m�Dw�����&@����n�]v�	�C������n2G���i���6y��iw�	��.������)w�4��w��D�S���.�O��U�#)�h�����/�=Tz�Z�X�C��B����R��pA��H�}l?��,W���W�"X�Zs�7��iq���������^no_^n�@��!�SGy������I���~���
�20�;����(=#h�b��8-^��1=b����I�BK9!F��'�
$�(YY#DGAJM�G����J�����}�
�"���Ik�*�4�M ���6N�������k�c���n>\tB����}������0�r��w��LgV/
!\�U���`��]�� �Q�ER|�nPF�)
|(I8+�^�F�W��U��}-�C�@�-�"�.��KN0N�[n.!����:2�!}+��:G�
�d��h"������g{��8v`����H�J��@2�60#^��AtS<�f)��������f�'R@�ljD�7i��K����@�7*Pq��	P��	����M��=\?=>���I���B�����T$F�&v=H�6�6�-S��8}E�4+��>����asqm��(O���Wp-0�����1s���h�H��x�QR���d`�7�dy|�}*���N8:PfMZ���f�����Y-=���(�����!�T�1�0���0�F2���"#8����Q���Rug���z��N�M[�1�A��z�t����o����4Ao��?�2���%?	9%�f���	���5��
EA�8�2:����D�����1`�?�?�����+�L��/�Ja�����m��QtzCa��pP�M��8�Y��i���B��x���a|��t�`��u��� pf8;�f4�WZp�OC��x����@
)��0m���wL���Jt��=!I���S��=����r6:!H�%U��V������z��C����������{��~�r�k1���m���p�?\��W�fR��������]���m�_�m���_���m���6O�z��Y�7�n�94V��op��C����T9���s?[u����wP��~wv��x�&�t$���L�wkkd%��?����@6���cS�\
���;��=#�H`�)��mrislo��8�9��oQL� L��s�P�s�Z�P�.�����v�bj�
L!����<�p<v��`F���J���He]H�u�/�:46�nO�����,,��.r����nl��Q=���.��������e�:��y��u�ny�Aq�
�P��x�Z�O�E^"��Crv#p���NS��W�I{�������D,����[C���q�8�i�Qv��=|QFS{%����F@�&�3P�����)�J�w�V��tB��Th�{9�f����5�������������-@���-�DG'��S �t�r,O�^�r{�~�z�g��\V
T�!�`sQ�0/����X�>[�h�[���N�d2U���.D����#��&tB ��j7d�(��?$�#>%R�~�{J���s�52����)�c8�te�Q8|��k.�+�����jm 00��:.A|v�0�/Q����Xd���9YRwc�9�R��p��A�����R��r:FT8]�NRFnu2m2������nF�^�:����s�F��7W�m��VN?V�Q���������W�v2]2�8�M}(u����T�L_
�s�Z�p w�4��q��������g8����~ E�D]�5���:��A���|�5'��r���U�]����:BL�{�ko����@l�:��W�R&�iZ�{��\�#�X�q���o �Wt���:�LnY��&2}l������0N�y:��p]�Q����(���D��*5��wU1p�1�,�[���M��>z���?�&�#K���x�(��&��?���"�!8'�[���So��6Zwa �G���A��}��O�Y{!\��O(�L�n�\���~X� �p$����8����8�rl���!m>�`�7��\+��/��G�2	�0x�n������U����������I�bq��?W��,}��)��Zr����I���vN������.���0�^�����dU7h��s�V��f�&�#���t${us���LP{����o_s ,2��	��o�;��^�FG�G�#:��tPG 4H�X��9�FF�5�m7�P���v��(��*�j��"P�}�A]a7��R�x7�u��#�6�� x;xs�$��8��t�.� �U��<�(�Ua��)���P`@��$��^��W�Y�f���a{�5���gy�S2��
���a�@����B�)��9]��`�m���$�����$]�j���\e4���"���b����!H���zM���uM���@���8VP��7���{�hd�c��)�������L]}M"?<Z��C������|5�L��8�P�C��F���6:����?	��PD����!UIG��8���ax�0�R��Wq^�x8;��a�9��RSV�jv��nc��M�h�:�4�wq'�7I�A	v�3�\v0��*!�>kz�[�:i��?*�j����L��0,�����{]6����|f��1j,��| ���H��
c�YY3�tC��*����N�Q2sO#P���v^���]l�H�B�����)Xp��~�U�"<�Lg���m�:�_�����`�;��A|��t���*���BE�����^��V����yM�}�)�Q������-�-��b�,�
8�T�.^��/�06<���X�y���x`>:���>���@G0���us�SnE�+���`�3��/�
���_�qGk\�h�u����O4)�8��y���=�����)s$����o��*A��S7�G�]0��xu[����*B����lP�T���`O�tI�seO�s�%!�������wu�vhL�oR$j��oh��Q�����O��X:%�!
F2��0h�v���@���0��$N�3�:�-b� }a���� ����0��[�mJ��Zk��6`@x� J_�.�E6gu�|VgAl��"�c�
mHp{�Gf��1Q�y�:F��V L��?�cQJ^8h8�����r���}7���g-�c�r�
�V�p�-�\�w���@�p���
dQ��Cz�&L���6E�wc��@
04���������E2f�@�����_��N�D�a�v����;l���T��I��M`��[�4<,WL������8�H�C��>�~��F����:�td��l�l�s[�?o�D���V@Mv�R�O���oV@��.�1�:����O�UV���~���T'k�S���R�;�}W[�B�l�t�����.�Z�[��P�4D��0V�y��v���#�����������@��xH�O���\�m]��5�/��
+�����p@��BDU�N��`���������,��G�sd{�,
o�B�v�l��N���Q���QKa<�:������~�/���"N�S����_J����Y8��L�1 ��������GB���><J�MS���c���PU���0��7u��UB�����N�Q�t��C��J�;`�a�G�tad yZ
�'���c�������^����=�8R�3�(`Wt����C1���V7O/K,����V�8��a��t��R��R�/f�����?+�)	�������U�t��tm�Z���0c�a���^
�B�3������&^4�yK�]�N�E�F�e@Y��H'�0q�6������\��gV�W4��!Fi��-�4���E���^6xE\��+� ��A/���"������y+>��>���k4RhW-��hUkP� &��L�m��h��T���/����X6)�t�{���j�,4Co�b+�VF�^��N9���)���/m�0l��%�N�
@Q�
���s��U��"��������P��^Q�a�!��U$�����C�����iw�������U���R�����|+�"zODT	A��u+��e��-�*�����:��y�u���A�M�'��t��;��R+G}+K�����?!E-@�1�����vv�9�&f�`�]�('L����d8K"�NM�����l��K6���s���������QD�����-	�^�S�gi���v��9�*�!Q��h�X�����Y������#�P�jQ�#�p�(���s8���Ua��YP�?����7wK�_�}�.��	^#N�+7�?UM�}�����q�'�����(����bO8P�<���������Z6o�}����<9�C�1��X+��Ne��Z��������r��-
u�w���,�!d�#��Z�s������!H_��%��T�<O ��La��c���+O��4"#��`��:'����j�~:��5W����/^-d��K]�^,�L�+S�R�S�����,�U����0����x.a2:D��*�%~N�E+���U�Y��9�-�����'X�B��#����v�P1A�=���-�����O g����������9����)2�FVpx/�����\%FR8�(�)JF��w�a�l�R��)��%5I�[&�f\I+3���>�(�w������-�C7
Q�d�sP&�O���"�����I�&>���H����>�������,y�\4�C�C���XC����l��M�K�>�"?:I���V�1DCy��5�<�8���hj{�['
��Y��'�jv�����\��Oo����9���/\t�^�*6���&1 �S	���~h;���
aD�3��`�3��yF��d]~a:�t0�8cH�7�$h]�C���S
�.�Vh+~>�'�i����z��Whl�j:�A/3V�0jC��,2�0��O����_W��<'�a�
�����{r��;���u�����#(������@�{�HSR��������t��	��3�����>�><�/�������u�Sy�t]<>>�O+�w��,��<���r����
.��({�&aWe��n��$=�+�����C$U^c��Z�SV����86�X{��0�'�����N�L���l:~ �����
�m�'��YuX��t)V.�"&a���FJ�VE,r��a#��~#�������b�9��Q�9x���Pd��Y�D+!��.�e�������R������}�F��}<#�f��\����/Y�t�^oT�Y��P~sww��)���M���������.o����!�>���&@���6O���7[�=<���MzN��M��yw������m�D//��@���%t��^n��K��}�����$��C����V�����4���J\�p�+�o5��Rt�U�����#|���nZe�f�P:��TI���k-�.�3#����&���*�o�� 0N���������0n��KM�h��j��4�f��������a�o�@`2Um6�r��c������e��^�P�T����B��c_�|�b��,��������G����y���B���=�>Xm2�S��������M�^�2�I�*���.�=����U�DW�]Ol�KG�fQ_j*x���X���.���{����\������:�@��[�]��=82�S�]_g��Ow�v�	��+K�)�z~(���h���^����{�^��+�����\g,�]��n�����%��/i�L���|�U���y1�<�
��������U�������-�������8~�<�Oo�~�_�O��������k?���OW7�O77��
��7��z*:h�pu���pH����+�k����}�?�<��z���_
������;�X���K==�#/����!`M����O�B�_��'��r�{`��\�����I��������n8S���d��{���,4��l3�v�L���vs���h������Bm������g��s�����w�~���	�oA_��/�G��(NV.'`PZ��}[�����9�KP��Z����]�����Z�S�����I��Vh�p�3����W��[�"����r�x/'���0�{��������w1�9A�,���79����f����5���m��8���-����n�{��g���K?@	rh�dx�E���(������s'�^L�u�����4���L^(��L�v�R��q�,8�ZZ{j��O��=1���c1�/3�������6�������Xpd?�Z+����������bm�T��AyQ�Mp�t�l�~��7�����X��s���
��ho���H���|,�-��w��2����+ojW-r8�K��|���Mq�|s�{Qb���e�5u�`�r�f/��nXW�*��55P�I};�v�Z�����N�b1�6-��q^)tEvZ�.9��$V!b�����;�y��\��q� �@��9�a	����Z��]Mq����)�s�X��K��2x�o�����(�Z�x+S	mY!z/��&���Qr{�9�+Q����2|��p>�pvG��J+�gNl��UX���}�}��������@�l`�I�w���"��7��Gh3���p�X�-�P����h
�Yc���r��*3�iaU���U{��;�f�1�,�Fw{H��K�u����z��g�X�,�l��g6d��Ba{�g[�x�}K=���`�'�gB����Vy���(�1G�.�#��Qs_�y[�}�wC�������?��-�V������Amm^DX�^7���wJ��&sx�)�%>w��k	�\������8����T���T��`�hT��SP=	������P��S�������O��\�fhu�����vx�=��0��+��=�r��[i�1G{��8F�����z}��	8pS����������<U���7o��w���D��P����y3��>�mi%�y"��v�f��#�xSB�1��llBm-�^W���LN�-���z�\*�P��@�qV�9��Z���������J�@`�;���}X���hZkV�s�V];%O��}R4�PPW��v�����vV��aj�
��Z>��|��"\;�X��@�F�73p�lE�����2�?���y��Y>p� s%�tK�Y�$���*��!@�|����$������i~���	�) �����I+;����	u���������Y��L��l�v��5^�jv����!H�a���k��u���N9D�}�
?5���������O����u���O��G'��E��/U�h�<:$"�Ub������	d�'R��W�LZ�����e��7�@&o�6EWeS�mIt���������j�N�!�UOw�x��[8�8�y�3��ep�Z���	0��HRz	�#������;���J��u��
����!�+r������;��>��V�,�01T9�:[?t���� �!�x�U���iW���LG��G�������gV8L	�&�9�����r<��3G���N������u�"<f�po��/9�vM��BhN����E]�� F
CM���Z���`6)�'L����R��W��=�s�=ABR�j��m�����3t�y�I�saV���&����.B�{�N���>�7�8X����1��=�Z�*�t\���0jc�a�7q7����Xb,������V�Ny��3o����Z��O���B���B>��#��+����(�7�:C~�$��m���x���ta�.�4�`8,M�Ma7_"����n��>�D��i��Q7���\zOD��<�������:��<���+u=��wE�����-u�!W��c�������������R����O+���lGG}��zW�7K��Ke����� ;�;+S����8D'����0��F��\��L���$��g$�}�PV�����.4�"�!�bwX/[En3j�Cbi���F��?u�v�����i�#;B}�SZWX�a�!�����[KX��=T���|.V�ULZ����]���}:~B}���~�� ��w�
P:���39����[G���v����9=���,q����=����@�_I�h%�I{�BaBYm�v}�2,P�-f�n
���b]!��/�q��X��p����Qy_���d�>����G��X�F<�:�E� ���!�(>���I��������(1��p�������^J�9W}�������>V����I����,�d��v�H�+38�;:
G�H��Zd��N|�;9Z�SY�u�����/�{�n��`k��� ���^pdh0��IkT�@X�Vv[��u�w��f!��=u�z�9V��5��k�G��j�-�"%����nQ���e�PW0��(��ym Z�JFQ�n���E��J1�]>88��
���l���$h���	��
������V]���Wk[gs�[>6�k2N�lFt�*,��K����H&�w��*{�D��K��A��@��8zHk!����� �VV]o�f�/���ia�J���[�B�#�f'��Ic#����,��X[_���^#�t5_
��skR"t�����a����e`��n7��wT>���:%8��������F ��3`�B!��������ReL�������*��X�.�>��?E����xL� j1����y>�mJy���{[��'{_���X�e- ��SQ��s>:e��TS�O�(�����^�-��.P@Q=�$�=EN~5�9��B��(��D�'�d��q9��<�]��������a=����u+�����P����I�����\���Ny�,PX�M��t>���8_�s�M+��*:8�����9���:nF�g@b����lH�iD`�0�\�4��K]�@��K� �aS�
���O��$��<i��C%�4��Ku��n��)�MH/Zf�OS���
*T!9	�����je�E�4rv��0^�=����Zw�����?X���.��!���[
�"+qS�����w��`��)��h��Z��zp	b��!|�X�b����O�l�����*���b����h#=�j����Y�a�k��7���$�7����O.���\v�xtZO�b~�.~�<�lC� �G?�)~He���:�[!�����N_��F����������E%a@W	�zF��D�����^K��K�j��������E��LO3�5`%%�Di�
L��_r��N��M]��5n>X4."P}��%,bN���zu�_Y9���t���PD�����[��X�5�.#��m���>�p`>�A	�1i��]������Vs��"17�f�,�Y
�5Q�.����/?'����LH@5��A�T�Ew�����E��2��G�E]tr����yz�f�����K&��q,S���:Ll���a��2�c�[�?#�ki���Ql��x����q]�=�Sn����i�_[�LN-��E(3d���fk���ux�1A�\�������'�p���$���*�M��g%*C3�c�����
�"?x�<$��Oq����5i�	~/Hv������� 7�������w!����k�R�ibZ��L���$K��MBy�r�'���Digm#|�U��S}R�{�u�0��_F�2I�$ODM�%���_;�{���(A$I�c��������G-�M��3.I;+�L���j	+9�wa�3��V�O�H�`^��YR��Mt�~�
��S��I����Ug�����*��X������b��m����9���z���u
Z�Lygs��QR��d�;�����lJ��4����)��kn_|�^c?Yw^v�`uI�r��
�;�Y���L������+��>"�Y:�m�ZO��&�qV��K��X�����''����$U���*
�U%����%u�V��JC�����k[
�`�����<T~��F���iHd��?|G=����Ao��ZiTu���Dg��H��V���,����-��Pt�"�+C��O��o�}�F��p~O�I����m�p>.�N��$����Q�N�9}9��o�!:�,l53F��#���'`:�tI1m��b|���@$�A��w���<�
��#FS0.u��Pm�=U&6�m��{H�~�RJ(�*�JG�fD3��j�����=�!��D�W#}���Q����I�S}� �3UOB����3�������{���
9qL(�-�,��T�7gF�<�zV�L���w�xf��.Mm���F��	,9�N>%��*�{�89%��|va��aF�\��.%y���r�rI�zu��/������%��u�b�og���S���b��@�6�di�Z���J����k ��X_P�� �����IT�!�Cp��8�Rul>"���c��Q|/�\�
r���,,�RaW
[�77�-N�Y-�"��[��,8g���&�K���}Zlz�y��"����6��F��N������G��ILfW�Q��C"J�&�b
d�3���44�0��e���6_��H�~�m��K�:�I�-x� �o�@��$��N9�2�p�,hy����n��.K�9�{����09:����J�{�������5)I�t1�H�hZ��j�9M���'�u�mCw�V*�16Ja�1��������^��#��e�$�1��4RY;�E�{�j��nA#Od!�y�������\�b���>��w������C�R��^�C��T4��i����Z$�tT�O��Z&��1�=�������H* �k(Fc�a�����jmA+��E�������GpL	��,_��L��[C�F"Tv8~d�We��:a������������q��+1
�6�!lz�M1U= 
�����D�(�&e��O��4
!0/��P�@�$������Y�P�<�zjS	%���	M�W�}�L�|����HS�P�!�Zx�3\{�����"W|���o_4~
fNi���+c���P��~/�|F�p��t���������:.�&�c�`}�S�������t���"�h�0�������U�m�'��?�~T��b?_AT������mD�7���T�^vm���(�J�������v}z�����0U����v���N(bg�	���MxrZfr���)�E$��Ld�$m�&��"��^V(�(S�c���:��O����?�x�G�����H���(:���5�
0�����i��%i�ic4�S�%�X��M������f�\*dga�B����C��1�
���h���|���
�
���i����M��r��H	�=OD����2nc�C�k��E&�E,+c�m��n��� �A �������-��'�e@{��m(}��:w��
a������J-��N�Bg�A��PV���+�phg?����T����qv�`W$�>7�4��me��j[ra�UY�mR�X�j��}7w�����<�V�9��a]�M��y�	R���QV�����;06�Z���]D���K���
�XGi=#��b�0����3��n���n�~X��.�]���UX��-��0 Rq�Y�'�I/���	R��|C#��!f�
��e�/���-��)o���G<��A�u8
9���Y5�v��@��@�U���	Y0��	�~�Pc�KD	��^�m�r���M\�I�M����Z�KN��P �P�ie2q����$�<����Z|yu�8H?�x��#�P���].�*�&�D&Y�Jy��@��pBn������� @��T����a$�7l>.����I��D���P��@���(D;�2��\	nDW��;u��}�b�
�<���Qh+��24�Tt�����z��3Q��[�%�-�����X�*�{,�2#�}��i��^�	N�6���$��W[p?��H�`| !���UwS_���B�-5@��ORH�K��(1�$9W������k�f���:L�1�V�R;������!���]��^���s'��t��'?������T��bL	����)-K]���(�c,�B����w]t�|'6
�t���Aa����#2�P/xr{�T�Y��B��i�K�Iu�2�i(�[�I�%�L���UV��Z;,+�S�����|t{�l��YNN&�5���H���5j c���;dD��{�%v�zu���2������$�� ������Y����RX����U�������~�/g�N��7������<A`5<����{�!����+']�BYv��2�")B�i�o��""�,\f����u'N��m�f�����7��M*��h E�T������v!7V�[�����{�B�dd O�o��2`f �|ozbtD�n�z�4�k�����E�X
�P�WiWA�v���.A�������Wan�����6�c)��L��3�t(O~��1y����~�N���R���q%��K�Sj�����d���� ��qF���RVR���,�����l���ka����'x#@+W�s��X�jE�'i�r��)�����r�S
��S2\�U��}�!l��	
�����z��K_*�gu�N�o}�U��s��[��dn�8�`J	w��Z�i�*��"�����i��D\�v�i'��2�Nq�I��
������i_b�0��ewa0.*�"���2���M�h�V7F�e7"�BdL'�7{L+$q��u�����[�xi����Ds��cR{vj�����q����IW2'������{%�����.8h�:����M�����{�%��L@���-R�4��
���U\�P�
�c��3Y��aq�HZ�c�����,h��p����#�C�Z��J^�N�r6��|�^��u����D
���l�A
�X=�g�&-��[;����
xuk���;�&�[��j7^�M���&�x�-���0������a�`b[��������gpJ�j�q]D�@	�I_JIG�������3��@oj�[8+A��������:	��D�{�Wu��,�S��<C/W��A&�����#K
�z$���ZB����qN��#�3�U�dc�*���e�;iI����s��E��5k���[�M1�#����Q1N�U��8����!�s�gk��d��!;rS�p���������*qx�:H@-�EcU�H���#���A�	ju�*�H��MB.U~_�
rH�X��o��+����u��	L��L�	�������M`._*����d���?�K"����<-m��7u�Y�-P-��x(g�k�>�BQ+M`*d��f��L�"2���F����P3�0^]�r' ]U:T�3aQs
����py|S���v
���:�u2�;�����@��]�Y6n�n<���"���Y��6�����$Q��0��bF����37�bI��e(�kV�WY��z��U��`B��g��:s�������\��-�%_8��8&_�p����k�L�	�Q�`��M���v(�V�L��_��]��W��=��v���O���e�PR�������Zq����&��������������������x=�&e��b�d}��4��K�N�BUpC7���G�(��z�^W�;��;8��<z��@N�{Q �5�����u6e#Q�@�s4���nJP�c��=����b��$8�������8��&I������-z>-X2�3���`�����fE�����&���(���E����e[�1�$94�!�8r���S]Y���\�"��Ue�Vg��-�����7W&��������!�)��������6)H���X����UV�e_�U���"��� �,+� �Es�C����f�M��=ay�6�t�0;��o3I�����n
�l����D~���m�d������Z�L%=S���@��h������.+�$Z�\��$u8�>���0W�gV�BsZ.���~����rs�~�{�{ |����V���t�a�l�����}QOs���9����EL�ty�����E�g�*��RVt������l��r��LUC���rt{"�Eu�A������OrBl����I�3�����<�r�E���f�^Y��eX�6�D�pt����l����I_����g!5��uu����DW)y�E�_L������dqo�F��d�Xb����� M��q��:~
>��&oI�g�$�#�(�M�#�����{p��^�+�4���Q��Q42`r!z!����(2
Q'��m������(9qR��Z�jG���2��E9t����X�m�La
��}���)���$�g�U*�]b���by����bF
����T�s����Ra���hF$Cp�!�!^�X	�W��'}]'k!����cg�������.��|����$aX��C��Y1�3����
��jf� J���L�c��?��L��e�������2*������������Y��
8Q��/"�&!q"��6����z����-�,D7�F��#�*T�����r�	 �� �P�+�bMp�Y
=�4��| �ay"fT$�b��
�G��%�h�Z��Vy$������?��M	�	�D�h�B����r�+��w����\�� �S�[����g����wS��~�P���P���`u���LX���/��U�4�������.uO��g�����[�2d�@/R"�|Kv��^)�SF��&��x���jDC}LSF/`��,��\�������u&����S�O�������G���	4���lG��� �1�Sxw]`A�[;������V@�D����a9��/a��h�6�I��vt���@z���e�� ��'�vl�q��,�M%+��b��.�������h\�i��6|����,
)ok�E�-7k}M������5t��,�a�o-�M�v�����n-��������J�U�P:�	F2+B�3$�([���"Wk�������?����X�\>i����!���4��|�2���0fWO6�q����C�H1��Q{��{�C&��N5����	���n�,Y(aR�����X�R��%T4���N0�[M�q����*`2\HyQ����D([[�������$�P�������<�<EH]���~����J]������t��W,�Y�i�0��Zt����RnSl#��"2�=!�Y�VW�����fsS�m�d�B�,b9J �3����B>�(�n����?~����7��3"H�$��������u���0}j?��2[�2��A}�p���7Z��a��8�5�4"k��������#o|L���:���b�P����`5:��.#hc�x;V������Z�*f�wKx���N�b}*����.�<�?�����lr�
*��W�=�T�p�*��z,�&=����Q�V}*�$9N:D��C��T�5������/
�IT{�k4v!��c��tz����T�x�>e����P�F�����YzT����lJ��s�L-���
A�:R��vJk�_u���,�(`��0*�}�RG;��P�2�T�������-�`n!
*�;���S����P�F�6r�j��T��aF.t����1��BF�����C��f��k~1 ���ju�����qNS��}� g���A���m�n*�;�A.��%������D���Bi@;��(/�v\7���si$1y�m�!PODa��{���(���N��5"T�v���{[�1�_�,��?SaPk%�[�`1	���z��u��j����D��wO�!1�r��L!Q��c�.$�������*���W4{�v������r���4v-tAD��������I�"��R���8��Ap�R��8�����^'T�"1��eb;���&�G� J�u l�� �%B�2D_������E���0�J@F�*�C�	�������h��$m��s	A����O���<>�!�
�v���dn@]m�� }'T]���p5����T�i�#�@����"�]�~n��.�������;G�,*�Y��`%�H1h*�� '#�7��8:��EG����
$��0a�^���:u<�^M��3ZG!R���t1a^D�JO?����ZTwX�����N��������(+TR�
���0������x��}��T����b�T%?���1�:~D�����:k��^�*��z��4o�@g"�A$a��TG��
��t�GHL
����d�q�
��|�o�����$0���L��~O?e(o�����^���k��j�>���a�^���S�A�a�~�
�����28�/)��"P���P��)v�M�~:��a���6��@A����.�t��b:��*O2Y
�MD���6���0����cC�\�����CD-UG�S������8e��uDqW���-��
Ce�l��g���2�I|B�"�C��C��s���y��#Q��H��kh���j�?����f��(�����U�����M�;�'�fZ24G�����P�$�:��4a��9���Z���L�T��"�:��vY,Y����9����u��c��@���������p���1�(;�����VsC��\
�����K�9�����9G��0�w�B��K�tbu����I%��du�@j!�D{|�L|��/����rc�0GJ��;v�����6�+�����IT��CE�tx��Z�jd,u�&���_��;����?~�*�=(D0���a�0���(�ou�$���� W�Z*���]@�����ge�u���EJ�����|���f��L6�YrU}pO�8����f7&��,#��	
@�hJ���PE��}?�(�����6�Sv	�h}����S�m�"���������3������B�������.�
$9z��vG��R��}2���Z��!��P�X�������<L:������?�a\Ga����p���>Kx��I�����Q����c�_*J��%;�0'�1�� �����
^�P�R*��pT�
��tU��z 
�'	�%t5�y�A����B�pd`��N�>�<��9)�
"�H�������A	K�!�<b����g�U�!}��]C����mO�P�BP�w��7���)W�`�("s��3q4�����i�R1p��7�,n1��j�]e�>�BQ�'���-�p�mH�.���0v]��3�����%0���+l�Y������f(J�Ng�6������;�m-�*��d��(�;$�h���+��H�\7h��hbt�P��!u"���^��w@�v��\�@h���i�TV�U&�X����������Nj�=������a$"S��E�T����b�-R�{D�#���w���x�CTZN�#��������S� ���B��}X��'`���F�>����E����~T3	���F��*��n�pV�����|�F�p���uM��B@���8V@���R��=9("�1Euq��C�o�i��XD�Q���h�������X �q.X��e��xz����c��s-�+�f(_�;�9u�9�G)8�
�SQ��I��L������W!w�O��e":7@�L�]��Mw�1�x���x�c�\�E��~'[�K�����9���{s��+,��!j�8����8�$+�Y��Q���z������c��`&���cd���:�yU�b���L�
]�O)��G��;u�+5�2x][
����_���.H��_�6z
�/(@F����a���T�l
# [C��4&�F�*�(��jCR!�s������(���SALe��Q�{��"3\�Ro���2'�gRv�NQ��,�c�'�L)sL���.�j|��CU��Vgt�b���fLJ.9<B��n����d$o`��"8@Z�#-r�Guu��n���}|� N�:�1]Mm
�+3��#�������UI+*\�PHna��!p�M��{i�Y�~NY���:/d_���Iy:qD�	�=2T������Jg�@��J:d����>��'���7���vF��=�@�p��<�!��~��D��Y��l�H���5�I�� ��:t��jj��0!F2�: �B�P2��6�"Q��t,���k����;8�w��h���t274����g�����g%<�3��V�)�*xr�u���i�"�p����n�?HW�&���hB��F��;0����^1��vM��a��A��%
��o��z����� ��d�R&���,8�l�+��m~W
X�S�{�9���s�S
��15�:`�t���X�����J���E��me��c,��D���!c���?����]�/|g����XBR�K���N�����.�o*��#�K���V�RT0`�L^r���9C��<����b{00��g��p���,_��9q'��9u�s'��A-�DA���A�k��6����7�D��h*��'���a��������u�A�h�����c� t�G'�bmT���5Fy����.� ��P��;e��u��
�Nmo��n����G��&O~��k[����u#J8��&��EW9���$����A+���
q�����}Q�:���vX(�c�C*~V�E��qa61�A�@�J�sd��!s�_E>�8F�*��tc��]�1�^v]iz�g����mLT4hy�d2� tN@l��-�.]�.���b�m�-<��&0���g���e��C��4�40��m��h�`�e���� v��J��I��P-�t�����[�)�����N������t��XUkp'���jo�
�DX�bQ��KD�>�jc�DB�.jOg��Am�� �����[�U���Uk[��1��V��������\�m�� iZ�#
F����9�%h�������@�_Y�qh��!0���X M���f���/������8�����X�Kvb�i�x�Y+�s���.s�Vb�F@����I�k�4��A�G�'��t����R+E}K&����op"��F�l?�V]$��~#_06�fWG,�	���� ���_�N1�������L�,YJ��`���G�	��H��X���cx!9���t��s�y�"%�O��A�/��5�$2����o/��x���0c_d=P(~���Z��0n�:*��<�<�UO�����d����-��r��c8i�d��,K���n�(A�*K?�t���J�d�� �����h��=����r���_�*�C�<�Im%��+R�\TP�����,����5�(���� ]B����x�����R6�7X�}�1-[,������+��o�'�p��S��W���XQ-�3�D}Yq#�������QG��!T�7��$��	�=�%�Y�)�F���j���i�+���K����jLM�S�(������W&����&�T�t�^-�j�� Y��LG�
����"i�����R*���Zo�B����W1*�OW��_~�JE�L,p���[�{���}2���k������Po`'a�������ABE:����=x����@58.���3~�y�t<�t��M��d'�S���9(m�������J^���Ty������v	68�e-� P"3�����.��N%S�h�#@E��:����7N����Y��r@�9�'�� Hv�,�dR�
 ��������H�-3K�����E����a��L�RpKf=&�DN4�������p���H���U��z8�GC��:t&`�}�F�,�^j�Q�~u���u�����4���%�r��������?� ���5@���O�au5�;gl��$����K������SVZ����2��?��]���4]��W����B|	��.�\����[���j�a��2�u����T��PK������I���^������(��^G�E@��K$�dX Q����i3R�����}�P���x(3�U������W�Vu���S��9��O����M=5�����S��j0wU+B ��&�s!�������_�f���������
�����[��Eb�����
���^�]�����������?�������4�����i��q~���_w��0���a��W�_
������;�X����z2�|x����pz�i����v	1�����o��}�-�������=��
"i	�K�����[�8���+3�[���a��0>���k<u���S��xb�,���/�rp�k�q��C��s��\ka���:���YW�x*�9�j*/>s�Oww����!�P�I�xu�M�6�Z&[���T9U��t��!��[p�o���^��������G���E��y�l����x��7,���.�N����|�����=�������KU0�]������x�,@�����:�t�+Y\M]���^��W��[��&9�I�M]ql�����������������_���B.���<����}rJ\��}Y�����o\__?��_��>=>��^��O�{�x{{w}us��p�����oo�o�����6���5BHB=J�����s�������������������l���?�����/p������N��qu���: ��o����q�����?�3<W8_���m��jI}9���7���n��c��OZ*	%�@�����=��?��n��o��O^����g���
>�����%����#�wu���=X@��r}�"�xQ��n
=D�B�xc~zn��B���(T��6/��B�5�(��>�N}$�{m���#���!�Q~R��m��R�?
�+��P}���<<�D?��"�M��6���[�h
wJ��%Z�yF��������
HT��F,$�W2"U�*�����q�#�a,��X�ei������_�����(*G{u���;
^�Vx.�!���r���;�Rw����)�Z��X�Qd��A*���#J��&H�����;�����v�a�y�,���N�5�DI�'���
��$����5.�8��,w�f�w��O�,�p#��Qs���-,��!��R�]\|�p~����c��
���u���sNdOV{��n/�h�/��I���R���*�����l����h"���������8
����������������(i�)u��o�.n��E���o���{�F��K���JN��T�b$���?p�������U�&=
���P����e�n��+�:�\��N~�����"�SM]��W���=Z���SB���K�������b�/�����~CB`	s���wwvIF)��5���e%/��!Z������J
Hy�k�@����S3��>�Q6�x���z	�����$%#�hA��m�2���
��Z��R}�~~A_�=���FC��$����n�d@�u�h�[��_@^��#3�b)���B�b���|�������9��~�?�w�"Ry�B���2���fS�(#�sr=.P�Q!��
��;l>���/6
��*�=���-,1~h���n�%��~X�e3��8:>�+�dfr��
�������
u�����3�������gs�1(O��:��/M(�!���0WU��8~��W�����wAs��l����nqc��1,�����j|l`F}�m���-����sRa��*���4�`�-�����cY��D����:���~��H�d��(RG#��
B�|}����t�[�*�+B�p�d��"	����5zN=w�#����?�y�v�����W�s���5=�AY������
�\�����vQL.�_Y��7�J���uU]�:5�h�Y�eC��O�z@��t���wXTP�����J�9���~�<�����R>y�����������s.��=	u�Vy���@j�zw_T����3��#H��kQ��!����rRk{�R�O�y6�z9���N��P�6G0��P�D��
�dn��<����<�M���c�Uj�B<��'��H��w�?q�}9��������������`��W�����!{R1�hQ ja�k��c����K:�-Mj%����(�y�#j���{��f������&A-���O�������0��^���$����Y�A�|sR7 ?VU��vQk�zW�Y��j��'�����ra��Zl���c����'GK
T����^4X��
z���E���c�a�w�-J����r7����I�l����^��0b�R�rX)�P>u���;p
���AO~�-�p�.d��F;��B���=���HK��$�4��<lH�q�f��kyB�5���o����W�#�U��j��J8D��%HR�����5���w%R���+�����}e�M��N ��*������v�D�y�xX)|T=k�+���Jt8������
�[��|K�HF�X�\��:;���3�F��������9�l ���h�l���z9�>�3��g�����9�]�!�E���>[����:y��]�����(�[����zOR��]g����Jk��i[W�F���y��5��P��z�����}��h�Wf'?�&T�)a�7F!�M��u����v�L+���4�f���Rl5������gZ�LY��s������������)}�U@� N*�)a���>u&t�9u6���d�����&���A�[q�`�U���w�^s�c�d����F�~�o@�����HUI���-��T::�Q0��=HO�W�Su��	�@)������	Vs����c��Uu[���z�'��6�]��`m����:��32
��q�zK��2~�G��ts5���������q�FY�d�ofx@�r�f����
L�T���m��>��T��K���.����3$�e��V�01�BDR�����������cQ9�2/���� �{o���G����FE���,W����_����O����H8��Z
:��(���������W���K���{�{���f��	�����+��d�'��;���*�flz��!�I�I��OF���mc|�����q!������fF
Yn��lt9�p�%i��� 3��t�S����|���,8��_�s�:km?
�/�X.�i_�N���]�c!����_�8j
	y?-]��;������2��������T��|������
N�v�zstW���Z�B'J�,ge@�X�=U)�_`u9������cm�uu���W�����^�����WE�-��f���tF��i�z�f�a�G��u3����rt������xdv���A��8�C=A�%��]��T5��g0_�������R��M�zs|���V���e�q0����J�Z����^F$1�@�:�=����� �F<Q�}Iq��T��Q�V�k3S��$��J��NFpGk8�j�~��z��Pb.��*���R0�Zr1C`�
^�.�R����f�p�
�T:��w�&�#8{�c�2��5d���;�y��-dhA*��o�����G�x��Uyw���7	�|��9�>m6K�~04U���^����)����}�@�qrG
�3s�B��I��U��h������j+�T��(�8����^G
8,�����������gh�>�^���	 ��,��	_
�l}�3���5�2����~L����/�Y�
*�A'��CM��!��6�
��U�����c}is<���^�q��;�����fY}�?avr�����R�+�8�Z�]��{)Jz�0���4���#|2���?��?W�.�&���Uz,��v^�A���������#�m�A�Q�g�{��PR��Z�B���})���������'���$��56���o�T)�.`�9{�f�Yh�y�|~+����{\i�I��
��X��.v�!�s.k�6o�B�$�W�,�������$K��b2�	6����P��`�-�8%R/sWa��*�������:9����>hJ}����]�yM�'�����<L��
�i��cf�p�yj�S1���f���.����T��6��m�l��;b��Tk�/�j�*`���:�+���s��D�,C���������A�)�����"���v:�L�:s��7f�6s������r������������&��-m*�A�D��	���j�fuT����g�2�;l�*E�T��f���/O�[��q���x��;���^��u`���dP����Q��u�����:�$)�:0U�,&��TB����D��C=� }@�|k	�3[}(i��LR������z����!9�q�<:D�����+�].�'��f;�����z�.,���� ��I`_�*���#cPo�T��l��>6���v����I���;Z����i��92��'�&�+J��C6vS�/�:��Qm��������&�?���g#�I(�����V��M�@>y%���iW�P##x�G?��Y�=�X�����	���_y�Vg�a������iV�6�o���c�CE�������*��&$���k�L�����9:�OC��80�p(��������uYW�8+�<k;b�e���x��u��&/�Zk����1��|����*��]�&�S�jr�,x�����3R7y����7�sOA�;u���Z�k��Z��������=M��l�t}�����e���\U�xB50�n���A��;ARd��������A@�TXs��cL^���x�Ej�9l�����Y�g���h��c#���W�)"^��c'B0;�'�dY-p{���
cc�P@_Rka������[k���A]�[S�1,w�yDU���M'��s�#\��f�}��;ZT���^��t�9��$+�P
�QJ���)
�\=+�7��$@���@Y���6-�I�E�������m��T����'�]u�L������~a�j�M-E�T�x�Q����q�'�cSE�f#5�>��Cg�@�u�������"��MRx_
.�y��*������q�N�������O�����><7��������L�K5���2ZC���y������C�Kt/VU�W�
��p�Q��
���
��\x_W��G>�v�d���Q�G�HIUo?{;;�_\^^�6��*+�+��U�h�f$,B��.2	����&N�55�zb
>	Rw.~O"��u�����W�#�F���7�m�|D������K���������-���S���/B�U'$K�9(�\v0����/U�����g}��*����c��aX!�no�0(:Q#���?X�����Q%/��|���Z���������j$����*�f'��H�����hd2��2��((��Z������:t��F;��B@��F�b"a�t����d�w��J�����O�l�x�=�6�������W'^�*9����� ��K��`�I�y�2��M��'�_�}��$����b��}��"�|�i+���K�m+U_�@e���F�4B����{�($��=�����4���%��xG�6���|� ��[l�
T�~%��q�8�S�ve�F�w��WxHd~�����'���v���'���X�h�������N2����
����V���|`�A�:C�5�$����<���
Jp �z�#(������[�p�������@�w)���H���0��$�6��F��H����9aUlR�JF���G���:��������1�_�{1�].\�����}�A�I�)`�tL^��ZR`�3����G-z�+����_�v�}��btP��`�����[R�B�s��;Y����j�|*UR��jay,oug�v��@^L�Dt��P�~��V4I�(���&����ATe��K�Y�d����R����@	�I��[��D����D=��l �@n���x�*p:0�����j�F�|�r:��.dV�b[��oy8��U)Wm[����}&�cZ0"�,�6���F�'�,��m9�@P8[t�d��UE��F�����b�����yX��.@_0���q��h���Ff����o��Qh0��>G��'�`>����������	?�W�����P��a:���^S$Q�wh��hi����?�W)��<�?���
�qSU ��X#�_�:?��!�����t�����\a)�l�su$�ngk�K�[<��F��_�7��g���0N�E�2~Q �9n��;/���5����"Bj���
J@j��Y�bI�	3#WI�5u�#hv��U��A����N[\���_�y���r5t&�d���9]}�����(�[����M}�Zy���; <xL�!q�'3J���T_���@/\P+L�{
�|��uWq/�X����O���`6�T�
7&Q�/��Fb3rj'�F�����d�����O����.-�*L�T^��	�:��o�����y	��1�|�f��}Fsp�?�Y���Y[S�y��&�	��ON�f������B,���wm�V������x`?{}H�����BY�7�`�����Oz�T�^D2k��CAb[]j�G���y��wg�����0���f���������,
W�!��?��������VzQ1Q����q�y����`������9���{U���F��/�V
��A��m���s?�f<|�0�\���-f��(p/|�j)��v�S]�MR=G�}���QJd{f�5���FO�X�*V'L��8����GUSA�;��y���m�q�Y~F�a����%T����
�5�-Zi��xHG�M��^��$K���=��b���Gb�wt����
��q�M�(��j4�J��>/p���zQ�������R�����^JJ<��~jO�z!$�m�1`c��[�
��;�S�.�0�4"'��TA����/�5��#4���>H��G��K��������*��cE�'@'�lEm�T��B3%{�tF1�F��`T�.�?5dG�4lH�N����X����y]�!&�HO�i�UJGL|.���e�F��A�z���y�{^�?��#y��`3��9�#S��P~q���������������Vrh)J���,JV�,�q�,��WG�C)c��tpE�dr�f7eYo�r�a4���H$��z��>,����6T��� ���-��� h�
B��2��+���,���%�v?�{��Q
o�(zC_��a�0��~{K�v�����������/J��1�&�{v�2.=�	%@�����k1�
������cV�
��A�����L�A[V��m!�����B�^��E;��,�t	j�> ��i� �<��i(�(�=����;��A3�G�r����*oS������G'�v&������������+vW�7��sw�6��D�qZUOGv��*�:'�������@����yL�-�Q	@s�5����?`��i(<+H�js�������NC9S�������P���7|�"������p�L��I�C��S�����2E:�(\�/�~��B����$_���f)��)R�{&&B#��eX��@U&�~�8m#�E��D�Q/*�]����m$���J�J�M�d0��ZO������0���E/�t��6�\Z��K��M �����,�0�� 5q�R,!vA
5*�Yo?A8o^@1��)�`�$u�<Nt��G����l~����/�����S�|`�C��$m�EY���0��8�Q��s��*���r�=��e}�������z}~+�W��,������������>���q
�8E����9��*�����^�,���`�T����0	��q_j3����A�)��T
um���_���s�����\&���S�u.� V������xC@](�����C�&-8�����1���uj�3�ZF���o �P�I�iI�\.����/����^�Un,�n��U���C���	T����R����c{j�X���yi�qk�KJ�!g�������Cr��guC`h���^��&w�'6y�N0��'�X^��?%2��F�5e���;/��#	:�3��>�X��~�_/p|��[���a�q��-ob�-�C����Yug�,���w�����p��FT�\����-L�HFb��GV$�r������/����Zdm4��v�l��%�">�}���
���1����{L���MT6�9j@�������cSd���������<�@>�����6(_TR_\}I� -�$j���������bf�����X���6%�;�$~N8���[�y~k�N4V�?{G�f��u��9d��k��y���C����:�V�!���$�
�� ����~���n�����n��<���E��W�lt�Ze�T��������y������
�z���V�b��DF>�:)_����:���^dN�fi����?��\�rUY��'d��,�G��G.�~��F�j�����UxkA6�����s���/.��`DeL�P|�MN�k�q���I��UwF_ ��_�}�nh�0�4��BRY��>b��-��s��\D����)�KR+�gn;��q���1�O�DF����1
p�������*�ne�Ee-�@�����vFVO��3C�1��KB�J�4#O%y�T���t��5����\��N�s����k�@�������
0��!��3c���Fm� fR��4x)R�O�v���O��E�y��j���j�����rq����N��T��f���ZD�i53w���|I���D�\�P���9�Y�X�n��{;�����4Tfb��c}����9��V,{��t������j|.�$v��<��khfx��W�$x<>v=�=4�L��5���~��.}q[JJhN��8����nG��Q��Hg��n��(|�����@N��(y3����6�'.*���[9zK��n^'�����
��zvF��rV�%Ab���k�!sW�q����m�MJ�W��c�'(#1��p
(�*UShE����:��QC�(�u4�G��Wl+`���w��
<���$�9��Z�zX�������o���JU�,0�����v�I��{���o�aY~�H1�{�C���w;��E�5��/�{}1U���^�'���TD2�uZ���PD�e��G���8�\4��J��~�2�Z�ER�@�~�XoS��e���^!�`���i	R�|��p��f@>����JwF����+��0Ue��F���$�A����$���S�K�S��1+A$U8?K�Hj�K6|����7��]�������U~�?����y��<�!��R�b����:����$�s���_���Y��b����h�D����;������V����"�J�����%A=:��,>�%X;�e�4�vxy��a���?��-d�V�������}�e����*9!��L1L%��&(P���%�����o�3�*b����j�� k�S�6�iT�/|Z���Nm����L,��sD�T0����hQb�)-X���Y�P�=��g/Q�D��hpljNJ���*{O��az'�(���1.���|����/D_l�U&�^���$}e;�c�D�)���w�k��������b��AC=�6�8*DX�R�e]d��9���?���,����^V������mUpy�e��>�3��52��_B���%�����Q����`�J"LET��~�o
�[}a8G��ZX�:��i"N���-A�@m��q��K�;1���w�:��9�#��M ���P-��u4��
��*�CT���"����*�� %�:F�I-�6��������[~��������od�v�Av�����w����d�W�E�~��\�q���>tVc������w�<�
��6��\IY~�l
&��J]K��Y���K0Z&�����*��M�x=��/l��(�e	� !t�Q��������zL�5(����n�����0���h{u��iS���a+_������0�
�B�M�����{P=}^��jm��e�g�h�5��t����b7{[�
>��
J�El����XB:'�J�"1v�����s�������I�w���Q�H$m��h:����R+�'���HI�3��g�����R�*��z8f�]+Ym}��,r6�N	RK<,�Q��;�d�o�S����hqWP��]=����;�o2(�6��/{p�	$3z
�U
[
(oA�U|�1�M@�9>a�Z�/������1eU�g�g~g�@x����A����x6�}��xQ���x8�+�������=-j�X`���F�:�nd9���t�������(oI�2�^vZj����P�h;%�a���q{����>�q
a���f��w�PS��$Z��\������:�H<�N'�/r������5o�M}LG~ox�M=��j�H�/.)U�>����Lj�>L�����C�J4�w�7���V@���������2/��'��J������u��pbj������� <!8�����UT��� ��x43����
uq�9��^X/�&���0v���Oy���6U���������W����2��NZlE�VC�Rj�9��w0����J�=�"9-:�o�9�@�a�p������%�"}�G��������Ll�7�p��k��`���R��2�
?om��&�K���}y1��P���J��a99����v�LO�N=5�����!���>u��O���.`���-�>9�mP
�+X��*��	c�+�~�Q��[�,�z����(-sv��lR������w������>��%A:$�S����$aW`~Z�S�Ac5&wE�����HH)d��@kg����^&��tg{B9�^2_g��b�mT~��Y�;3
�#e.�B�����������7����+���#�p�n����	��A�n����?���;���"X���It�����;v���]�L�����W�
�8����Z����Z^�c�|K���(�&�������pb*�����A���05��S_~����I'��s��2g�@�.���4=����U����{�����B��}�t����{�K;�����>9������\��d[H�b��B}c���7�'w����������^�����-&�Z���tK�^����%4�03�y�q�K�0:W]	����6���I(�����X����9���GNI��}X7����$�T:�@�����V'��y�|��d�'m_O����|w[-�9ul�h���U��y�(\��� ,������e�P����'xQ�d������D0~��2����~]��_`��?`��&��'=���� �����F�"��.�mm���+��g}��\�H���[�@�	s��#)��
s�J�
�ss��Vh�2�� -��G"�eJ�vy��72�v��H&aSK$�L�� �X�HUw��Vx��M�MP��{^E�<��#
��3�1�y0�G����|)�Da?���,��8-��T������I����HS�z����(a����Wm*�����
���k4��,�E�.	��U����7��J��k8�3F8��dY���/���J�8�����(F\��N�(b�GJ��R�#���g
o�9��E��FF�0_�^�������E�HW>n���Q��	������=��{�3���jT~r�"nf���+
����]��bR��[h'B���c��U�i<{��]�0P�W��Q�Ei-�'wZ��|AG[����/G�-n��X���bD�D{���	2~@�����AL��D	=CS�_�s�f�f;�V�zcm&YO�����oY=��������;����c�P��
�����_����?F��J�RU}�ssFJ���qZ�&^�
[��'}%��`o�%C(ri�	�G���H(�QI���7-��M{
m�\�`�y��v�>=w)V3�K�m![Ls�>�����h*��J)�Y��	9d�}a����uR'��b�@�i
_y��Q�m9����4���+�
�R������~D� �����?�����T�C���T��s&jyMvj������g��d�/��-��2@������h�����n�����"�j{S_��<,"7���(�mi������t�0l�5�����C	�������������5����mz��'�N�J��!��w4�.����4	8����H���Zw&�^������:U��j�,X������t����;��M�{��>g\����:��[�}���h�|�S��.�W���?Xc���Q���
 ~�f��;16��-��@S�2�t�r{��Pn�Y�s����+"����Vx������?S�R�7�nc���Iu�c�y��~��O����HL��c��
��'�N��
�������`�x�$]�FalR3����L�u]*�m�O3F��_��W��b�'����`��z�"����@_���/��F7�����#<��A�N��������k�����_��'�!�����,I�������79�;�HO+��O�;��z���?UAz}��G�*5~}J.�@�J�X���Yj�"����+F}"-#q�	��_�(.�+,�Q���Gp���q<%im�t��?B����Q[�(�ro������0H���0��1��������#��	K,C�Eh�In.a���f\0>{�?6U�oa��>�I�(;��I�,��GhK�hc-�)=��$���D��BP]Z� ���u^�$.�[R������\���eA���L��Y���H0�h�46;. ��,i���Y�X/��BZ��{{����ky������9���G���	Tf��=�,�	��������[8��/N}��?�gj�I���NO�)����G�� Kxz@�q�geY7U�����j�H����Z==���
��F�Q%/��*��k����G$ �>;�zz*$���?'��u^r�����-�cz�������
D����&KR���s��������|.�Ne��vZf�� ���97��^�N�J��Eq�r�7@<8c�_
������r��>:b{ �}h+�l�J)��=p�6���W�@X�a3��3($���@n�UU_�)��oNfeQ��xK�����{��65E���1�� ������A���,s��K�Q_�g��
�V����e��"l��G�����D|`WhRGl�_�Ho�$"���|4T�[����G�W=�������]��;�����JVZ.�����������6k�?�Pc���g2�_e�����=(���}���6�6-6������������W��C��=t7c�H�>L^_�J=��n/�������v�n�����@	
)�%udp���a'�F��T�w=t�?�!��{���f�wPn�����
�seZ�rw�Ec:����t�^����U
!�6|M�������g^�0'����x`���L�=���������I�TIo��GCK4��=��%�u*#^{�Pe��s"}JWN-
�����w�pE�c�ks#d2��v#�:H�
8��F����������_	A\ot�F_J��%��t�����~R:�;��J�9� W`J]\ ��?|���>q�M��-9"Q*a��`O�:A����6�RG6o����vO�Eh����z����vo�r�%%��L�� ������B�AcwRe��YQa��rx��SGe(��s��G_�1�
Y^~���lBA��E�*)
���4��<���P���A�Z{��x��yYo�w�YAE`�1�}�	����*�6W�y���F�o��8]	�
#����3���0�73vY�"��;5�b���'I�����5�������+��a�w�����I���!:�y��tu����H��_���Y.����+�Mq�@���u��u����v0Y�Z��GV��;|`�H}dG����~����PUc���'��K,:"�o�,��
6u���R��UUT\��>kB���m4�	�����H�������
��c����X�5-��G�V�������Kl�H����s0�����!�Z�7�d��-�wh������Rx������~L������U$�*2
P���T���P�1�f�zPX���`u
9+�	$����m�R�}���n����7�(x���i�E����
_�/*t� ��z��&�����4n����r���.�~�S���3^3�R�z��M=����n����do�A��}h=MP\��U;�8(+=+��9���U��[q�tf�g������GRQK����P�l���
��z�^d�RV�03��*w���z�j��:C%#����JB��M�e����f�N�I����TV�
�h`����@%wW�4f���i��Z��;�[�,�T�	4$�62��n�U���N<s������T����F���e�T�2���m��"�	.O��gaWE�su���_7=O�%>:Oxj<(i��O�����0��
��SS!
�/��tv�P����G���Kw���(��H}������>����#���1 �Zp�D;m�g��F�W����h �Q����
.�P�2�*��r�W=]�B����A�P���V���Q��c;��������Ek ��!kz��v[��P<���z�����{F���x�&���Ab4� ����R���, ���������h�YJ�M��,WSp�<�P	
7���+�D���rL#
�Z��@�� �a)N�w �_B���>�E�$��V�:�����y���t��O��P�h�2��=k]�A.�28YM`t��N�%�1�fTKc�������&X?F���+�3�*�c�O��W'&)������3:��1v�nbP��7$�c9��|:��8+�P���#�0�w[7���<�N��Y��"���og��Hdb��@���r�����z�WP(��!$�E�
�/���������y�	P��I��=J}`���A��F+���"�'�7��9�Y��l&�*������6c�M��t���r����%	y����J�L�N����>���i�s.z�(j����$����]F���G���l��)OG}qyT� )�ThZ�k���w:'sn-��L�a�����s
�XU���P����%��En��fe��bS�B4�PUh#�q�Qi�vE1Npd������)�&p��,a�Lb�83v�F����Q�lb��m���1��Z���3P9>63�,V-���U����3V)����#(����$�a���(<��o�ktg��U"��a%�m�O!c�x��G��Q�����pp�7���_I��A
/%�!e�"I�V��/*ki��`(`���d��~�v	uL�:��		�>�3���Yj�&�[�����!�j��IY��y���aI�}jc\�_y,���bf62Bw]''��O�0U
����>��xgN�d�,����:�{(HU��+�)B"4O	������U���w8�����|�+fX���":a�
�:�������WK����|���	���`'��E6u����jF��6�=��0F�k9�
����/�u�7��f��+�h��������"wG�=�E)���&�L�h����Y[Z���W����6'7�^�x�����VL3���Y'������g[�U�"C�����s	&,�^��/��|?�GU`���������=�G��I�� �:�����0?oW��A��������jYfF%<��u ��0kMT�XS����dD-�d��t(�H���=�Gnd�8�������6���B��i���9�
�fg�$�����������t��������fz�f�����0U�'~0����21������?t�q����a%O����n���[(K�$�"�D+�����G�@u6��+1B�P6���ts!��CfO	jY�bx/���\}k�r��{���Y���*�3m�:�ym��I�O�MQ��z��Xs�Le-����:�m�Ka�i�}:��6�f&�'��|L�\�(��"����=E\���-�(:Zv��x��2.�����P�z���O(>����KR�-)�H5>(��?��~(������YK{�4���j	NcA�vUC�����A����`^���2X{��z~_�����R6/Sd�?	�)� ���DH���^����1S�w�_\�g��J�Y�X^���mA`cb[L9�`���������j���A%M$hv�y����hO��^�������]�-T�������._�)�[�z��	��������`A*f�o����a���l|5~�?n?���VUY�o���� (a�Kb!����+BG���Ij��S���"x)��{$�a�J�������m��0�b��wCceZo������W�KV�p�6��\���)��Vw;1���)3��h��(I ��"�ZUW�����h�QYzN�X��������O�U������GH[3�-|���?#X�P�'z����S	���n	H/}�b�8��<S=8'}��(��]A���c1hs�,����i�X ����)]��e+��+5l����_����"���+�8ZZ������]U4M�����C���yXdN�hR�~6n����`�������{�K�I�<�>�i��E�s���cF��Usi�R�����VB�LZ�7f��a5��#a������u�)��j����������i��3�z;��x��	�������) w�$`��%�,@[�������9xT��QID��{/��H�gh��*�Q� ��=~�+�BB��!s���On������xw���c��7|����Q��3�[��z�\[�E�a�����yK�xtf�{�L����<
� '�F�D�����h-�r��J�r �VeA��+������Q��V��g�)s�O]{������x���L����p~�V+<��~���4CiW+�Z�� r����2�=<	����fNP��F���x#��%�.���a;J�c
��)���T�D��r%�i&���3��BW��py����s�E�Y��J�K�(P����Q�rk*���BG�~��7��@B-T�h5���1s�i��U���S3���%Hs�fy����DAlU>q����x>����}��A:�YMr;��!���1�Qwq����l6���$mGYn �*�L��qYA�N���r���=��O-M�xC�6;�")���|s��O�{������*4)?���?�}w?T��[������D��8%nC��h �T3����MQ��;�1��.�`a�fc��X0���W�=!�N�?�����<�k�B���!'�3+���D>���R�������\�X:�\m����o_�\|X�L�����	Ni.&9$$/z�NJ�j�S���~T��-L�X��x�W�"dhC"�n��@���F�	��	��������&]f�P��'����k�(�~2^PU��1G��a�>q����:��g4�	�E{�#��;F'�<�����7��Z���K��~t5$,u-/D�
kU];gQ�9l��:wy����0��TU�W�����LV���Oi�P�2��%Hk{w�0L���8/n��N�1�F����*����������@m��������i��B�``S���*0���]��W/�
�����i����}uW���E3��E���xt@c�-�����N�Ddf��5 ���:H�v�����)���T�3*��@�����X���E�D]o����v���{u���L<�� ?�%0������������������(3#qR�p�������Y�;.�VJ����������a�P��\���uhHt��>������o�[�W�
+�����\1JIZ
�����+��o��1�������3�������$����Fd�l��m�M����N�U6�{�6+,�B��`�mT������9�=_���s�8X�Vy
S��k���������Z���`�Hl�r,� �17A�����-M�0Z���7S{Bs�h�Z>��V(�����������;�+�(��K�gR�f�������DP2�~M&����N�R'S��Wl��.G5 i���� '�����]��!�T���u��k��;�*OR�:$��
~{M
��-O%��'�L��aF�r���sys���U��z|UaW'8[-��ivg��q)�+�"��/M����PcMF-u�Q�~��:"�����`���y�����QQtYC����t����4��F0k��+��A�����-g���A�q�����l�\���"ta}��',��
k��2�6�I�������pO���-���=���@����z�P���7���5������q�@��%��
���P��_{LJP��uH�����>����'�o�S�t�5�Pt���Z��7��x5��D�a�gL���iaB�S
f����E^,e�Z����A�U�r�wXw��Y���4�jo�g31��!�h
[vDh���'��#����B���:�b�b���O*\��6���R�R7r32+�]4���S�p������L3���p����6�x�.(,P��;
���� ��*6;�Q�bt��SVW/e��L�	!&6����.���k������\�T^>�9�W���b��U�4�?�%~��
��C'l���+�������<��K���N=�����K�It'4�kK��'D)���R��6���XuV�����b���+������
]m��F��c1Ch��C�����'����(�E9+�I:6!��_u�?�ZI�v ��V���9�����y��t�35�.D
�Ro������c�af��J���:��Y�z�C���T��$a\P�e|`@K>�O"Mwk;��O��3v�+�~L�����f��7X��U��ey�`Bm�\�qP9e����B���V�%����v���0����0	�ZA��]�	�jJm��z��	M4��u]T�9���Py��'������z���?��n�g>���>q#^6���up_�3c���Y�����A��#'Dq��]{Q���N1��>��j}�D����?ko��	���R���#��VRO�3(��;�coV������e:��s��	Eg��6�p�#m*��_N��apr������
e��^�
y����K�`U�6�'���Wf9�l�]�m� $���iY��B\�7����L`��	#}�2@��L+,�8���,[��������0��V�	#W,JX-��|< �23]���d��}Y��=\*���)Nc�������3����)�i�2����8���T��7��V/:Z�>+N4�aU��9�
��	T��tn�N-�}`�"�����C���E�lp���(�#H��P��,���
(Y�f��[�C�~��������m�X�����Icz�	��m-#�k������h{7��s�C�E,����]PI��6x�o���b�i���RCs�<�Z�v�X�pW�J�"���IQ�S�$I���_ln�n�Uo��������p�Q���!�#q�\x�4�G��X��QfRr.@H{o9zU�����N��r����j��,B���l�T�"��>O����h;%f�L��_qr�^{_;�i5�1������f�f��z�����c��:����]M���%w��k���iQu�t���wy�M����o����}���6%��b�N;�(,b�4��v[�E�SO��O�tx����-u�e�l�d�#�K�pR!��Cc6b<l��Y�b��� �P��n�DE�c��^�3�����H	�8�xH�������)$�p����blt�9��&����"7
�d���e� �F��D��	���lq��S=����N���H�p?�0eI�O����W"L�%sV��%46F���x����':�2����=<_����O�$N:udw�����=%���!�2�fz�:�*F���u���]j��9�����28�Y$�����{����
��j�Pi�?��`����S�4�hU������Sk���oq����������6.���@�HV�tN�Jw��Avq,C,�����
��_��z��8m'%��*N@�-�"�����C�+�Y!����i�zkw�4Q����e�'Iw�~-�����z�6�)������������&�NF�VzTd������S�3G%DS���H�0��0�s�A�
C����$�����Dx:j��4�k��LZK���F��H� �mMx��s7�}�.�/�9�%���{H���d�V��%}iE����wzp�� T��zDP�
	W�j���
��qQA�/�c��`�����Q1�%�j�"F.�����Ve�"h�,YM��6�t
h]���Y�i<�`��_���2+���T��MPt�-_��!`W�Z��q��]��1���w
L6m�����������4�w����;�����oq�yo	���#��5~D��������;9�YaZ�z_x�Sa	��4����y3)�G\��a��-Cam�S	�g�+�j�L�P�Y������)��,�p����s=��$���(����E�r������I��[�dZlYY��*��&��l(������<|,�?�2@�>����p��J�08eB�;_��<)*�P�'%��7D�����Z�!t�Iy�j�2:����/������w�Y+5��v��$w
����}�D���$	�[�V��lP"}jc���EeV���NT�[�	������B���I��%�F�8�S�Z����M�������0��w���u����V��U�V����2��:<P��8
�*����
xN�������{��!40��K��hK������.PJ���)h����!.J��r\DH47e������A��r�bsG�������
0��Bq�b3)_�Nh�P�7!h�D�Oh;{���.��]s#�I���?w�t;@1��D��D=�1��B���P>5P�������:�����>�)�'���k��)�px�c��$q�rTP ��g��0������8a����=�TWM��;�5��ju����R55���)3�c�'���5�6����u�������@��30��XOh]���k�"Z+<"<p	���	:�����#�W'+�v���e��F+���Pr5�������n�Q�8Nf	��>X��)#\h�/C��7u�~��`L��`�KV>�)�8=K^}/�V��h�h�����?�N��P����:�3�d{�8��$����9�3K�5_�A��X�k����h����f\Q���d��
��Cmn��C:P�k�l�n��?(�{�e�����DOK�^�'�>w�Z��(�$�M��a@�r�{��URJ�M��S0�GyL8��X�D"�����;P���]���v�9\�����)��o��NIWG�k�R���[!��F���L:j)���a��T�4h�������.�_�k��/+�����H������~.�Y�u���2~��m�
�.����g���E�xx�^�����m9�9��B�� a����D)�����>���s��V�e�>/�[���)���I �K-n�{U��&/������QC-�`�X�$40e����� +'�;�y��*�@lF9��J�H�`\��J���q��*����c���q��>��J�U�4�"�*��
���l��H��v�3s�u>�>=����j������!��	U�e���V��H���q�EQfRy,�@5��������f�����*!�J����E���"�&��Y%$4,y�>�V��j'�H�V�c��e�������I�)-��l�L���P:UeqE+`��*/�[��%�������<�7B�����A�tr_�7�rxV�:���Ex��SS�Q7����'Dw�TGzx�h����T�q������qX��5V���
�o�6����@A�Ad����p�U�]�s�!2��I��T������",����7��R3�3�/}�j�������CrG;!D:	m�;�����j�Pq*F�����
�Y���M����12�NY�R���ju[�E����r��',�8��j|��L��U�<
xA���Yo6�	��U�A�Lh��>@OB+�)��o������"	/�B]T�c�0t�=s�!H�&�
���	�$����73���^�g�`1Z���+uC.��x%n�Zk�/7r%�hZ���z6]�����VFt�������QUQ^4I���`�M,%��l��@��)���Q�)*	Tb�@���Q�L ���gk�8�P�YS�	O��9��r�����$�Y�3?�W�A���������V�O�(�ER��r+p����P�������O��Ui�*�9(-x���sv�G������?
H�5���95zT�^�Y;f�.oiG������L�����ke.�1�S���8+��N�@}�T�{���gK9^�-��DQ�1��tE�������(z!��I�o���1�
p"�j4�'���(e��p��2q�!�7Y����;W����FyjC*�T�J�^'gy�:.@	M���N�i�}��7��:e	�����;�����)�LW 8
Xcp���u���w����L���o��dL��#��.d�����g^�p[��&��d�<�|�6�pE�u@�h9f�P���g������^�:=��?�*�I��������g���FKB�3
�S��?���I�5\����1�8��{��x��.�V��W�E5�o QR�6�T}�B��#�������`L	)���h�sW~�����x��A3u
�Q�,/�-�F4.��I��5n�G8o�������Jb4l+-�ZX^��)��'YU�|�+�Iy��H���2)%����a�>��>X��Du1}I2��nay���V�!�M������5Kj���;���c	��?���D��D��Ta��9m/���.��+��i�����l+g����]`M�6�{
��Q{�D�;�B��8SZ8
����)��SRz�*Y�%��r���{��i+�_�(�����:����NN�6��@��t���))�>��F��$���z�J �2�[E����lU����	3N��'`v�:-����H$R��:�����@�C����w�Ep���0�8_p����f��k���1:���&����)��J4nW���zr�����&�������8�c������O&���:��A\R�VB*++��6���Ej�T�������OwB���k{��bp���Zrp��}���?���;�v�d)���ODJ��$.p�������ll����1h��� ��O'||*�����)ee���m��QZ�W�6a��H=)����5����w�5����1yi����GM��e�4�
�fM��$hEV�+:�!��M��]@t��Z�	������pZ"l��PbtrAZ����P�yU�����2�fg�����;��p �,p�}�� -Qb�3IP{�hc�A|&��	�7/��*�������~�rY��8�t�.����K��EiX<����!�W���,����K�Xm�67!��W����4>����B��������P�A$����A�8�&3.������g�G��z���I�����.4��Xf����aze���EZ���@��}�a	����u
}���`j�g���4W�K��Q2�
�*%����U}���I�����c1��u��^I�zV;=R	��E��&WE�8��c��X�Y4,a)`{K����'��)�c��`���v��r�O�2!��f,*��B�	�e�k��
P���kP�K���t�
�{=;m�
�LTM��5�X�E��i�/`z�
�I�z�4��F��d���2�x���a��5 ��-�!��;NOrmv���wg�QB9�Kj\��X�%3W��&�VGQA0o�K�g�Zr
�����mg�O��P��:���oy0�����*�P�����:�TQ{�V�\�UY�`=g�p����k;
��p�`<z�����R�P����V�����L�$������#?�*&��b�XA%bU�E)�C_��AY�\{�8�����+3��[G������;�T�������.��Rv�����?�'������b�g�f�����d��q,�FD����6E:zF4~~W�+D�bD��.;�R=[x�9�}6�XfN:����	\�B��Ff���,Z�:��Z��L����'�[��%�
�@�3��&���-�vw���7Z��4F���-�������\��%/��#�sd ���B<��<���)'�
���:Bvh�S�^0����a���Q�p��%6SN7�<��_���:I��20')���R~������/�4�!��O�o�+�.��,#OR�����(�hW������&�h�������T����b��#��|�B��I�S�����2j=������)��S� e������5����rA�|ZG*��rE~$����a�����H-�wCc?=�(�Z���j-�A|9���q��V��k4��{�D2�]��,��*,�m��i�������3
�� p$��5�#�XO�7c=/�?_��Zl�q�lT�)�k�>�I�]������KuBEB��I�����Y�w�Wl��]������W�r�M&��P�U�Q��^T��d�-����B��"�(��Y��O10[/T4rT!����q3���Dq�`��9�/!����=�����������"��hq��Q�=�(a�zydd�%�������1=��go�M���&��eS����������nm�;3IF�ow��
F����������h+��0��j����P7U*s��
[�$��dJ�zW���|��xZ}���O���d��0�3�j��j��h0%�uL��y�*�L�_����_Yb�G�U3����(������	�o[F�V3��TifZGn1z��I��p.R+��;E<$��"-)��d��IL7n�s��Q9�g�A2^�$^g
a4��+�Nf����uJ���Z��j#������
\�9/�-yvF������>vK��K��Kb�Y�(f��GOJU��g�-i�;a�K��Ka��|�lJ(��Z�?�<���7H�����:�����j�3��2G��,"����Yh��Az�/��e=2��JTFk�*����:�#+\��y
+�Y����h�1�U���9���%<�w��/�yG����*��.�L�j����� �u�&��sx���B�/p��G48��oq���kh��T$r=~{�����I{����N*1�[���8�����C��0���5��.����=�����iK�����*��%o�����}�+
������7�	��nV�����i��j8��z�:Gf��"f]c9��oQ��RS����o��Z�K���N`#p�B���%�b�2k4S���1�*��m�������o!P�����M(J<pn�zL�h�=��_]�Ao���4���/��W���|Cvc��>4f���k�O�?~�n���O����a�h�!���0�b�/���"
{���
��hs:l��EU�����;��"�&�+�pFic*��Z����u2�;�����7�7�P��CM&|�\��7|�#�e��_�������FO8}G��\6�2P�jO�(�\'������G����z?�G��	"�d����� n]5!���'����R��**N���Lh��@R�o���������Mb\����2��DR$/�j��7;�YU'}���*}J��T�zC�+�HP���Y���M�ICI�A�0��������]	+��16j��%����A:��P�!���u�5=V<
-�rT�3nU��Z��Q�z�����]�;TQ�*����|*�C���R��v������T�����	�<�:�|�$E�p�	���>�	�hX�)�E���9X��K���X�}:5j��Mq��iL�XR��,%��9%����J0�L��x�P�	������0��Z�����E��;��=��s��J�O&��P�;���Z	!
`�Ne�4V���0[�����^��?�P)��o+��O�e�
w���	�>J���E�.qtaG�-{Ia4is��"��AP�`���2����U0�(�F/��MR�Y� 5���N
��������\�8]��j���j}��_c>����Pg���x��='y\���t@f:���N(yys�����p�p�"��^M3�6Z-Tx���]��?��$TeV�g������p��fd�0�[
fpr!gZG��������d�3�����!���/*�����$��1�3�%H[�����,%��q��O�����:*�
8iJ��� +��� ��8�(�py�0Y���J2x�'&ITbr��QOP�J�OR��`�0��O�/uXM}2��i�����8(��X�as�/	O���34����Z7x7��Q[[��6I���.���`���$p���gp��=��6�a���R@�JL8������0[WS,:��d����O�D:�0�%W��$�r3Lh(��(�CQ��w�����^����iH����(,[������dt�`����R�ZdmY��p�P��M��/���������%�=�qo>����#pWX����~6$��u��zG����z|��R��;��	�K�N������v����s�*/�
��E�F��Vu�$�r�d���M���?���>w�2-�����*#�6��� �����=��
�,��nJ�b�d��@	2#�B�t�,�������>�f��+��w*��C�A�_QE����i]�:��X�>���&0l���6���
m�Y�v8$��������&����6����hq�V���$��7��s���&�	D4�id7��J���5��,����M�������?�� ���s"��x
S��h��=���8
�T;������B���\��V<���;����HO,�4��%�B�P$��>iH	e'�����!��H��:��u���av����xnp���to&��B~�8m����S��zbF�F�F2k;�@K��=��v���A�OW�S�MR�t�����>,Adq����q��W�J���B���<�#�u
~�U�������������6V[�V��1�R�rI�$W9�aw1�L�
�H�����(�I.!AQh�n�*kT��C{�������4���I���2(�I'=�E��f�����3�)�1��&��4�\y�T�l�M��f�X�O5Z�Z��<�����%GI�p��Nr�ha^b.�n�{z����.C�2_#�:����@�����u=��c�lOR )A,�E�X��P�Ql+(��-+�y��R49�y\_1�f�$�Q��WT�n]��N�N�s����,���#d(�P=�����36b��VO�2����.�tl�AI�f�yDI�
v�A�w0���d�"@��
�%�v{��6�~��eE�	��`K�4c�P�1��D�P0��,�+js�����2�!����_�?�	�'�]{Gb���*B)<�cj�$�D�6S;=���2U�����q����h%�� �^�@J�A��`-@���X�KC�W����MC����<MA28����.�DCh5o4E�*\`���d�@��p�
6��0��
������(��pm7`;�H�*�kk�w<��<�����}�� ������-^���@���5<�s ��	�����:�����W'xTd��������L���qL�R��8���o�?Z����V6S�K
Z6��p��x)jO��ar-�{J����7
�������1F�lg[�@������S:�%j�c}Q���� ObY;�M�R���%�!K@���cS��>��o�u@`�& ��E��gN&s=JcZ�T�,D�U�4V�E����@�s��i����&�*��xtR�B��!2!l�R(�f.%�`6%I���F??��s�@G�<���������8�p�(`����K�R�����c	��b�����J���`F9�ZB
���4
�Z�F�������8���x,!�C�����������B�A)�I_B����24�����L:X]���A ���3,����(p�e�:%��:
NcYSN������k���n>W�������8�=��	M��2����p�@$�G�������s.�a�������f�����v25����Ap��]N��o�@��^	Izy-���E�5E_�:
�|,
���oQ�~#7?���]_\��g�7�}��m��H�^2UV��8��bH�4��9���A��J]=xG$=,��-���������m>*g(t2��7%���
�G��(vR!D���J;�*��"4�O�g���(~�4������$�mq��J�
������hk�0z1�V@�v���\�d�������X/u^V�����,,���<<{;!0,'X
���&��.�����t���	�O�)$��p���|R$c�e���uu������R3NGU���dub-Sh��&y���������h`�	�8��=�__�[�1%�F�M!;�O�e���=��u�y��9Gn/�$��v���	�o������+}x��`>h?16���{-�X�7���/�`�L�ld��+~�Q��J@�����Q�<�l�P�����$BTtM�	��,�oz�C��5y��ziZ�s��j�.9^	X�Ua�&�MY�����x���'�Mwz��%�`��V�'��F*���������4���)w@���4��Q������w-�f%l
�*9�YD�-���?��;�!����J�<�=���aP�a�j:x!���[��d�J�����������H}B>�&J#�S#]�?���B
%������H�i��E��2��L�&>����w��:��'��}r��n����D�����tu�LU�<�n��ty!D�QD��q�����������$�Zg	�Z�Q�b�Q<���0�	��%,�E�)!��PjO����a��9��|�g!3~I��m���Iqo�������y�yp�5�V�KG���������6mn9��FH�u���9��K����&R������9������"O
������#�BK�_������,H$��A���7�2�����~���D/����mu*&�
�B�	L��r�{����?�Du?�w�y�$�?N��;XR��O��rJ��H��FDE0�&r��6;�y�s��������2�s$����7+�I���A�	���bu�!rW��YC��������FE�.))X�Rvk
OS�8������U��S�4B��F��(1�Us������Q�u�`���U��g�Ti��lq������Y�/����Z��X��&�Q� ���O]Cd������(���f�����%�*u�{�io��
�d�2a];����#�������3�c���$AY���s�Fbi�.��3�
���C��L�M���9�j�����<���H�O"}(�+�wyM������y��t��L���������u�,�
*g���(�8Z���"(�\��Wz�g+������Zb,��X���r-�S|XK�&��Yi]�P�+�������Z�6��B���}����:�����C��_�P�/V�a%�'*X����B�=�]���K���G��V�
������"["bh\=>�R`����!p����cUSB���#�bt[��Si�;#9��z���SG���~�Z�2�����C[�@-8
���q���;B�x�7�w����C��/%��`�K�
��^��0,�e�<�/�{!��"%K��j�
�]������$�NuRp	6��������/���
kx�-.�0MB��6nck�N[�{G@oy�L5������z
�����Rv�"c�g�(W��,�x�(�pj���b�9���T���t��		16�l5�	<i*F�AH�g�����>wk�����?�(�F,q[��)�,�U"xys�������Leh�4	�����3�L�v�����?n�+94u'z�e�T��~q��Z�|
�'8q���,��'�[R�Z~B���,�
Yf�EK�������YP����
���S��������c�!���������}�:�ld��������<�4�l�@�~�e*��c���+���VY"+}�@"�	����5!2+��,�:n9aK�r��@��-���/���������|Tw��8�	T1W�<T8<�)���DJ����ZTy����I[.`�Q:k(����cWJ��cW��L/���p���y�!����-�u�4�����mB*4qPk�
�Q6;:Z4W?�
��VS�m�%j��\/cQ\J�
R���!��%��eRB����X���O��_��$���Y0{G�;��Uh`>+PO,6���Y�b�8���yU����s�;����Q��H�<�5& G�q������P"��6���eS� ������x��|�&���z&�p�������j4����sBm��*��V�����B9�4!����B��AHX��:��I����F��w@��0���X�D(aP��@�8W�������!nS R�
�OOR�L�8�����A%/\
6IER$���0�����z^_D�����J�n/�n�B-����[/�����B^��f�&nB��6A
_���Er_��u�7W���D���,$�D6#"�����|�����q*�m{b��}x�%���@��.z����s[J�'�.�Q�$������8]�L����S�G�]�`�m��7���f�P���|\�J^����q���O<�����$�c9���P.��i����7�g��'�2���ls3u{A
�����
?�����a(N{�mh�0\
��(�_���G�ChP������t����5(a��i����%J��z���?
� ���>���c���X��"<[%�&��8����i�3V���D
�z�C h�iPb��*�R:��D&Q,��on�V��|X$*ha��;�{F��?)�I�bJt�\���D�$y��lV�8��>%�}�C���,'D�z�Y��6	7��L�4JC�1��`m��<5�9ZIqf'���iS~ACA���@��"��5��1Lpx����hs�I�;	as��I���	vB6�J�����@������/)�K����U�m0�?�P=�:{��0h._�����c� �H�B��$�mo�$;�\	��W���H�<TV��^OMV��r����d/##�;*�.����1U3x��6UXBS���
fj�=�;0w�b)*���YI����	N�b E'J1���"��.�����������C�i�1+�Z��&���G;�7���	HCA����``��/�����^
{�z3�t;=�,��89�����d��CQ��w����6P��EVn�{K_]V���/���S�{}��Ce�C���m��ax���,H>�5��N��U�n�zx[F��p`�@yH��Zp��h-�vV8N� aW#��t�2�j��0�*�`����-���P��hp��>U�$�&1������+��)u4r�T�p�t�z1��c���@�";��Q�6iY ]zJ��8U���h9�wwi�H�)���9{����m��2/v[A���M��{����&�i9�W�����?���z��_.;k��?~`��9l�t������2<����C��A�P��I���\{�q�����\���cwt/���bWW���`a�-M@t�j4u� K���c�@��|����]�������*����<����`���l����������Cb��b����d
V�D2�8o���(Hsp���Xam�v�9P���K�"�y��
�\���c��nz]e��\����L@i�F	g���Y��%
�eB��K�R���������������{�9����������4U�����?���~�[R�;>��2���#dP,Y	�uHu��J6������A=���6�z�{X�����880�����i?-���L ����m*3t��V��DS
�� A�6��"�����PZ���|?
��B#��*�q��[���)�s n�2+���L�L���D1)���X6��s^�����FPo�������"�XT�2{LWB��O�������m��}�.��b��^��FP��OA��e�U�����W���m+����~�~���@�o���VP�fP��c�����Ig9T���n>Tvw��:���\�:T�G��������$Oq���b�H!���BHHq����V��������������pX��B�=�{�I���1���������'�fGr��c`q�B4fd�4C�� b��mP��r�T>��������{-�F1T�T�wN�?Y_uc�2j�,�m�f�'yp�X�c�s�Z��xP�������7+�b%CA��t�y��Aob���M�x��������xP7��`0)cF����s������ �j�45=�
�� ��yfa���������W������cE6+4�_3�X@wa����M�����x&@���.4���V�#4�7��0�i�[Y��
��d��Fb��XO�<K����9����!�p��l%P�����bYh^95	���I���x��^�q�����v���������R��������	�/�H�r�v$5^r��A����Ni/���t�����Bm���k��PL��!T�f�%q0�:����M�	������W�"`a���a��)��Py5t bh �8�fN�}qV[H��p�vv�j�o9���(�:]�)���U����4@��:X��5cj`&l9e]Ah�\#�c���H�<���/��z	����ky����;G����=>�7�z�*�h�w���-����a�}��=,S�b�����~����V�����m+�b��fx�=��@=</�@=��<m�VOw�'w"��+���*�Z����~����T���B�+h�AG'��T��hC+:H9��XJ5<�G�U�bM�W�Z'xp]�Eh�����W�El��R�-
L���,-�C�vjF������FxM$#���Z=����a�_=�/_U0���";.�����t%��v[_�n��� O���4�>���VUx0!*)T�c�s�,LZ��	����"�fL�M��8!�g��A�Kw��!|y/#pkC��((-�5�e4�w��������Y�O�mJ��|5jOi-�uN� ��)��WM�Z0���*~T����(�pp�	���bH�5#�t���v�b��l��k�xY���o��Pbi����); �\+s�������B6��	e�x:y���}m���A�S	8h��h��f��X�@X��*�P��������y�1>�~<�� ��P�`D
����D�&+�R&�h���{P0�1U�aAG�T���y�Y��t#$�y����F^$�e��R�����c)Q����
�6�BZq����0?�^�La�^8@����'�P�m����]������
�[*%V�������Y���q`�uL8C�B
��8Pa(�i'�/��������:���z���cc������G3�8�ol'ekw|�>��qeb��?'kV��`�<^t����C�q?(?������0kv_�c�� }HY���5�W���rU�S#V@����X|9)��rl8@��3����c�	8G_Z����@�Y����1�d7�u��n}�NoA�G��2���G���~��LR~�1�pp�n?�����b,4��2~s9E���f����wt?u�|���_/�8�O�����`!�D_���gw���a;�t+��<f��P��VP�����o�{~y}������m����b��P���oO����}�[�{C�d��F?��%��mU<��k���z��=l��
��q���>��~���P.q��)@�����wk_�����Ay�����e�a6[����3Jc0�s�A$��lozW���,��I.^�2��}�B��k������2z�����R�����b-�<���s�p�l��G��{W�C���r��dp���;����D���t�[�n�8
$)=F�����S�Hxr���
02���t�<��:%�J#@��u�A�������qV���a��4~�a0~9UC�(��q���-����@�����Og��
��5����4s���eU�zVG��������r,�e�����<$F���H�-�I�p�������\�nZa7�'���|���B����R������yWr�V��P&Gi���v�P�x��p�k���5��4��d�b�8i-?�M���}���A��N;��V�I���x��[e��u>�����kn�C�����Ew��V�����>���0���NEp���=a�;����OzwW>��fP�"B>�.��~&��&0�
�8���]�����x����V3��y*�U�	���
�hP��E�Ei�D.)�5��5%�����r�
��=��������<�a����gE���\�C��
�+.;�a��
��R���c���Z�Zs���<\�g�����g��@c�����r�K��%'�A2�qj	g�@"�x,}:�c������bag_�f�"�;�i2�eru �a\�|HI��T��L�(%�4�5G$���@i��UC[/k�,$��O����A�e�XO�fA�[���i�����c���P2��.�s�`x��>�B���JY(���=��+���A�D\U��X�h^�z�x�Q�!�)�����f%��U?:��C���fB�H'��Z~�<*L�h��r�mY.	�L�A}��d�b��~���Y�q�oxx��}���+~���V�T�ow�I7�?�E�1���$�8���Ey�	K7����&�r�B�O���2��?%���UH��BS�����8�K��wn�v����U�T����T��*�K~��+1������B�};�ux�(��g��03��f��3�r��+.�G���O
�}���3@��U�X	����"B�]�~j�E�	�V�Pi{%F�n�������)g��������=IBF��
:�����H-��������M�C�\]^Wf6�R&���v>u�����P��?J�Q�.���S��ar3h�T>��F����>����Bs�-h[�87��X�S��j+�g<_*'>���#���+���t.�5p�X�������E	Q���'����?]��sA�����-����l����O�#��#�tyz]��A��+\qb��0��e��PU�Wp�BB�������u �-��H�G��p�~_�V���-����~����`~Y������
�M��R�W����0�<}��p��D�d)8������S8D�������(WSm��Y�&���
��0~4l������'+�)��cq�������R��B�h��
��6��b��t��Pdc�[��,�ul��[���K��X
�4�JC���;9P?����T�9��@�=��X��{1Uaq�K�8�`��<bJM��b�����%��A2�F���$��a���/;�:5�x�k*=@s�9i�"_&��P�z��M��2�Q>a�
P�oP�;w(��?����<�c��uD��H��|��JM��ceG�('fl'P�3O��Gg[o�r��4S�@�(�s@����o%��N��@�e��b#+�,H�h	F�@�O��yP:�i"���}���T��p�%Y��i.��M��`���B��~<��3���a(v�
O�����!D��%M�%���)_BA�|�����kP���yZm��n<CA8��5���EWl�x��c����<<��@=�=����t�L�"���o;��h���.=�UTP`L����i��-e���!�z�r��aX���P��zm�5ot������C�����R�c���t���+��!�r�v=%�X��X�-����Co/�K���P��<� ?��c�P|-�<������Z��Law#��0�A�Y������`��Hh��Fe�L9`FDk�i������t���+�����"0faa@ -.�9�#������c���]��E,,���B��m�������R@H�����-,�e������v�.��'�7H�����]�a����{��u%�S��3O���G��\��*��Cj@!�l�B�dF�t5��j���qg�sH�����g����G�%�&P2�y�&���'N�����,�n��}LL��!I��-=��������n���q>�E�T�`P�@��;�hs�v*�^;�����W���*�����Y.���?��,���2��I���I��}#����)ecU�(�9E�����_����������t�j2]�[s����o�4#�{�c���R88-��8��P�*������[��`cEU�X�a*T@����\��������C��>~�D�8���;���?�����Gy��<��d[VE�O��������8$�_�B{�3�)��C'��	G�-��n�r��/�)
c�T�tX�Vs-�&�kH����( 4�G	;^"���p���`�N}��mZ[����
��e�;<���`�h�NkA0��R�F~�c�)���t�������X'h��r���-��(��X>X���
�f����� �{j~P�T���AT�?���$����S\$�,��4���}#����d�R�.m�����$��fVU��lz�"�K��;Hh����$��i��d�:v��Pi����xS�p��'��\������UpH���"�E�i�&Rd�Q��d@W����f�����B&#?U�/�+��JJ�v9�������H�j�$uQ��p�3V(D��hQ����B��_���P�J>�G���0�M:�e�~����<������SJ����3��������@3�����]������\��}3�kWJO(1yxk����zuOG
Z
���?��|�r���'�����5�n���]��G��|���j���Iq0��P'/�x�V1���/��"I��{z=DA$�\i����_�(p�aiBa�V$�j�����_M���&`F�����9��U����Yb7�q@n��Cz�G�t���e+�����v����8+���~`��ZPo�����G�
T	�9P�vP��U�T���Z/��U�*��P�]��'C���7��oY����������n��f(������^"�H2T�v��[)���A���[ew�+��Z��V�(�1��Ej��r��Pfw���n����SPi$����7r�T��,wwmQu�����^6[����,����vVP�FW���6���>��h�m���q����t��hC *�	K������~����v�y�<?k��������\�?	����"�ev���F����WV���E��������NF�?��N<�����9!�5��b��
$DvJ���y0��P����8d`�L_�$e]�r���`�]	����a�6���:n�4������A"Bj�Z��j��������>���p0�D��p�T�/��F�H��X��0��/n��g�vK�u�|JwO*�\XS���y&x[��@�Vm��iTHr����F,��}�t��E�/8���z7p��03�A�z	Z�""3�b�t(KD
I�b�P�F���(�������f:��m%��gGA�� ���.�X]DK���*������e����a<��@Y�DS�Lo��8(��Z��Xx�y-�p����8���Z���`���hA�T�W�����~�>!	���IR�1_�������k�4��b���[N����(���L�������^���L���+�;+ b�@�v�#@��
.8���(���=���?��
-Y�����`O[H��(:F_es��/ �I>./'N^d	�n70���,a���0����T8b��9��G�������q[N�cC��������8P��8�j����=D��cI<�a
����@��w�,�m�n�tw������u���`����Sz����{��Gp���1���rA�y����d�Yg�#J|�=h1r&�9�(����V ����/���tlO���0�j�w����9�N
sW���^Y4���Lo3`�:��S��c9��agqF���#��@���R��P88#��6�58���7��
��3P����o�G��n�|�y���Mty�`�0��
t�����PvI�M���.}��S^w�h���V�M��N3��s5����w*������9��1$^4+�#�@�Y\�� ���[L���=������3]���?�����T���*G��
jg�90�N]�=?�eg�d2���{�F�y���������^'�=hg��pp
8%������
���UN@R@-@��t�O{�`+�t��P��r�h��P�2�Xq�o�D7�r�����W��A�>K�ra�����o>����]-��c�`�2�c'�0��*�m�Pb��FZ��>,���O��1������x*��t�)�]$l�J�*�s3[L96[+�)�)���i��I�l�)@ZX�f����X� �sV���,F��������_������K!	���n��1�F�^���!.���@���\��������-s)N�%I \9D/Y@��~�|����H� L���jb���Q6���2�y,EP_����+�|��c�S,P�����+���=������?�������2��mr��}Z'���C�N�{���h����������?�MU��~�������y����?C�W]4��Z����I��������3,���>����V������_!��[���������������O���"V��"�E���g'��)�����H[�i3��"�u����T��:���}�P��o����f�W�����?�}���������S������#�Y%����N�`������j}�^�[�������Yvl��ok^�
g�O�oEg���l-�k�0��S�`��d�F�3�`�Vi����t(V��q:~
U��������4�o��_��*?�������g�C��n��O�	~��Y�Xh�R�������_��3�SW\��%��	�$�I�;f��Xm�vQ���<7�T~_s��f��>R
 ����)��`Rs���)�[���J�;�8C�vE��!�r`En.��A�2��*"mc�Id���7�U@��_�s,�^�O�z�c�h#@�EK�A���h���uDu�0)����W��M��sQ;��0�N0�N��dl�cu�Lq����3���%��)@��4H���s��p(G����	TO��������:Di!�K�r$��P_t�rKp���W2|T`���p�7�U$��`
�����.Z�K�^L����:$���B���IY����C?�1^#
�`��`���?��4�B�q��I������0N���%
�#~)k�j�i������l����gB�m9V����s� ��]�E.����%�{1��w�r����r���
1�������n?x�C]�6R�����V0.���"p��o^s��t��!��R�	�����Zm����S?,�K&(?�"�1�5��3X�����v����(safKU�d��{����
�j!��Az��6�}�7���Su���f�����-L��Cz�|&p����^,<A���=��[4!����0�e��+�a�������L
X�j87zJ�������V0l�h��in������+{u����%\����aB&T���;kfg�]���<���Z�W���@����J��@>��G�����"�U�	
Pa�U{v�%����y
m��w�pp�9z�-�e����v�����+�����LOg����&��xa����mx��X
�����#
�Y���0`��C�@�'5��6n�nyY�6L�)���(���C��XBEj+`�%���xbk��@;�^W�P�+&b������CQ�?��d����	��)�HMZ�k�&��|{��u������<i&�3�eb��G�=������f�L��+Q����_O�����X]��}�n������?2;��U<h�k����;u��FbM��a�Bw<�����p���������������`����� ��B�Bj�VU��~�N6��OI�^����������R|v)d�-�	��yeuf�P��R��pU�>A�2�E��u�I�qD��xU�8G�#������������s`.�����V���C��A�.�Yo�Y��'SS��l\uC��9�N�w"O]CP"Q7f��:�3�20(��5��ZA*l\_�������s7��<�5��H@�M*?+�$�$8�Y����:�F��p����|:u�l[�Pd��%�����|�
�%k�_���Xa��[���4�Mv-�#F�"��Q�,X1�O#����r :�F$��S������1Z���Y4&,������-���V.A���W���r-�H���>c��L����a�������g<m�V9k�@��	#���-���9+�t�ra���Rm���2�vTW�����j�@aQ���q�KQ6a�V��j
������Se�F[��f�R�[�@�a@��80�Z2->����"fq��`ls���8J���'�R�[�����N=��z��y�v���Sq���������~���P��_��:�y�G�S$������k��h?����,���s���_����<(���?���~�[R�;H^T@��i�*����p��\�}G�G�������J0�f�>�/���?���,"eF*T��_�CC����Fo�����������u������a��J�����i�}EShu�� ����������������
(>$������M���kPe~m���{�70n^����9�:������p�vq����l1���}��Pe��#T����C��R�������Z����H�����TP���]Ae��U��[����?�POw������������>=D�'��v?�)r�s�6���RP����k$�@m��6{��i++��_c��l����]�x���������������i�V�D�_='V��$C�~@�l�<W����7X���s��(d_eF�9��d@kI�f�a+�P�FYq,���:����[P���b��D@%~o���4)��U4����22�4���&�%e�U?r:�Cr���.��Y���8�� |�����S���~�%w��@.����Z�'GCn_��L]���wT�������2��eA�{��@=e�Ae�+D��5��YU�W=P��zkW����������V��Z����z�IWO���exD���\�����e*�7�������f�A!b<���{�� �!��0����Z�`�
������m����Q7��&���f��0"�oCE����m����H���?dK��j�����2@C=��������e�S�?>��@�����&P����i�����w�+�^���i����m�"W��
T���d����A
�?�����#����s�qA�A��C��P>��������E�w�!�@vh�-1T���
�t8��q�9w	��Z�����I������[�e ��qL��A^�`s�2+���iY0����F���
�EP���$�8{��E��k(0����6G>��p��Z���;����4�+uJ�0n M����P��M=�/�r��(P<��k�UW�A
������U��)`�]�� x� 9 FC�&�tj����C������/G����Y����lG[:}W2Z�#���r|;��;�,b:"g��]��:�!2�Y�7� �U?��a�=~��?��]���5*T���tD�P��}���P���D�*�3�{��*���P/����Z��J��vo�'��-�zypFp2���!B���l���o��{����j ����|.`���8�%������K�'PsIg���(�v������25�I�fyI�Fa#;��C$��������1/nw��$�zF�Z8�^d������i����������F]�kiU��<�Z(.�N���^#�G
�N)V1�b�� �F�4������/����A�=��C��%4��n&�9��P�U�e�M������n#�m�N0@����Y�����z$��IE�e��}������o)h�����j��0���?f��,���?�?�O�o�vR����
q>�?�������������S�_�����~���#��*A��2�E���`���W8��~m����??]���/��*����������D,�_1;`wrLgs��������w�8�����O�9���#����=3���V4G�����\GUs���oH����3��������t��v~����	l���G@������%v�X=rF-��;�������5 S���yx����N�G#T�T����+�v,$�(��;!an��x;�I��qN������>�F�f�l��f�9�^�s��L�����WX�.
�6v�So������!aAE�W�`k���������
U
�i��'�2n,�=g9����k'^/����
�|&��-��\��]���^�x~��^#��#�����-��sl�M�����[KOH��"�X������svm�$�s42a�&W~Y��Xb)�����m}QB.e ���b	S.�������m?�8���V]�YN�����|+h��8��������Mr�c�������{�j#r��3\^�@]h���i���3�Wz��7�-�p�8��q���
�7)��F�I�I�i3,��a"�@����p�#��?
CAE�W]b3=Gq'B)��L02 	T��%��B[E���_������j�����J��=�C�"z$���������M�������B+�rK��)�;�E�/z3��9����0z}�O3�paaC�Z�XT�b[�eY
��N2(�>��}�)�����b�������1R���
����f�.k��~8A�]��RQ���%�s&yskmY�ys�|@N8i%���[��r 1�e"!�����������\Q<ON;��b)2��
Q�\����F���������o],����\��*q�s��E�����/)��Vwa���"���K9`������/x[-6���6%d������{��&��
���9�8<I?~j�+|+������\��;
�0���������U�4}�"����
�4����,����T�k����]���,�h����0t�t��$tqs���iD����y�M�}����fa[��0\�n,,����F2 C�.@>��d��M��A9i*6�H�\����#�I��CY�J�s]V�c_����pxuk�x_��xs���[���nU.�����
�t{w������>pji4p�G-S�Aw���%��������O�mw�Nq������������~����N���S	�TE�^y?�����5���QF���B��	�F�(�J����\��.qV��[/�Hr�m� lr�n����������b5�>�h2����F��������I����T7�����:�\i�C�Z�\���00a��]��9;�����)������Y��������r��^&E+���a1�}����,���ld;e�$z�����"�S�#���,s�a�LB���v����N�M8i��(|�������v�U���6��'v<��X�8�y#��{FV����y�S����J:g��%:L$;�Y1.)yu�VW�
(�v�9��_��xHht����	�"�9$��x}�����G����"������Qbm�5��i_��\(���^]mI��Y��Y������!�y����(�L-� B��������=�U}�k7��(�:�������?�2pE��_I^��O�n)T��y�<]�����(�q��ub�g��b+LK�_��c9����s��0\g8XV%��pl�3�G-����
��7�=���}(!R�M����d0 r?
6��g����W�*s��x?Uu~�0���^9�
t?'�-�����-�R	}qK�a_37�Cv���2�)�gy�C�����+����m�Hg�v^��&�[I�I��B��wE�g�%q�`6�^���U���cP,kT�w�N��`���I/u��/�+#v)�������8�^4��	�'��Yu���G��4��Rr�{�k���m�S~4��,'�
��n�
���������7��Ok1��i�GZd��H�Ai����	#��0g�ng%�����3q��X
l��]N-K��5*�=��\x$��W0|�E����rNQg����
�v��`��.��NQ1dx}�s�m��;i���n=G��j��Xn��!	��'~�"��|!}�������d��U�W����%���w��r�����.��z�N������Jf
u�,GY���/�����Q����A����C����x}�������� ,���R-
\���<E���s�NG(��t*�H���X�3�B��� �������q�^,�?<�O��6t��M���Y|i~N����o0����j)�G���[P��I]�O'����j)�����rU���|p,��"u��'.>R&;���8�X��A�6��B�mK�yc���O��W�
��~�O�\��Ov����/5z��IZ:MC�����M�a:��MR�*�c2~u�n8-�� ����;������B�B%pC����po�$�	g�E��x�r���d[�e��C���%fn��B��cn����e������k��[�"����.��;��?�ZJ).�w����@}P\RT�N��)k���:�J)�����
(Od�f(~a���}���~���[�
]��A�c���������0�o�?��da�T^&��h�e�ql���i��.�s�!OH)�j/st10���T����0�PR�������w�B���t	y�	�.��<��I������9�;�����@�r6@(���,+a��;x#��O���h\�n+���,���
7���"���I��R����\��+h��*0���]`%JM8�wq�����RV�6&����K���9]
`2��'�p�	��T�,��;��oE�8^�e��8�tM��Fe�d�����"a���H8N���j����n�����K=���07��u8I_	�-�"es��gI�i��.�0�e�e��hz�Q�@�$w�7��CS�1��!�RQ���0������6�g��S���Ul��(z5�� g��Gy�a���Q_i���U���4�������8 >�3����C�p$}���5���d�h
�ID?��y�U%v�m�����p��������k�����O�_K��h�qn��`.����:��s�s�L��95�^u#-�����|y�u��g���q�?5�S���A�v���a�g�T�����j�1����-v�W�$�j��V�lt��p�u�Q�����m���]L�V�.�� ��#�@�����Y\dmzuQ�������42��,V�~���T�/xU��t��;�}vf�8v���1m���q;1 �����K�H8��C1S�nX���2�})�V~W��2fX�S+t��a������f�\�v��u��)E��*�����DO��]�L9�f�nO��S�c�6Ke�GM���Jd��{�t952��k�Y�@��L91�a�W��(��l���un�{���dkZVe��i���+��A��j��;Gf0����`�B�B�S~����������:�������|WM��K��z���S<(�Rd�-�`X��G[�u�������k���GcSu��	RW�z���aQ�{�u+0������[�����.��E����2����m�D���.�1�B�o��BvG�q@��y&Xe���F��sv��aj�z��:Y������P�OU�=��C��b����Fu�{�����U�%������Py`�P~��W]�M!l��C�w�b��,(h#�`B98�#0����y�rpw�-���
��a�>t�:y�eu��<V����0�	�$��_H�c��|a����t�	\������ln)���g�Vt�D��/���G���I��m�>��4{�����#&#��.w��-	O�U�z�j2��D'y��������Wq��	�n�X�F6������u�EJg�7#����#�+i�w3�R�~������G��;,���q@�F��}����?��[��D���[i�zH��������k������)���ul!��t��;�!�z-����XY�h��X��������K4���t����������+E$va�U�������b~�B)�u�������I�j��	y����F���5��s(|�M�I����547����=����[�`����F�7j����M�������3sQ����7@S~|Il���\o$�����7��Qxs��O��v(qw�>���GY]��M&Oa�*	{7�i�1��L��*��u�y�0�v��I��r��e��F�}�g��V�f.��`�n���z9������&�di�Wy��S�	���J������ib���j����Am�
DE��A�[�B����5Gq��2����[5����`���f�'L�B��l,�K\����'V����Q������Mx;W���4�1$�mv-46�Zn\�uE�S2dwnZ|��l�,Z!x��^f}NZ��V�n��2�d{n����O�\����\�R	�1�5��:k!
i�Pf~
�Gsd��WR�E�;Qv��@!��~��n�(��rf?�9lo9��S�,��F����e)��d�]z
�����T�c��*<#��C)���E����}&f�����Y���J�����qZ�\����.s��Q�VX��nS���xs��J`jV�����a_k�.X�:F��{�:$
���>�A��}�fK���hf�$[Dv,���Pw1\�����.�y&�7�����
3�!�/=Pw�����ij.u��vT�)����|1[�D�MV�;�t���������TN�en�����:wZ�,2d��S�:b;��md�S+f�)3"�QN��"�k��������)p>���O6���z6y��_�����*�t�Y��B��&�k
U>9g����$�[9;�[�#I+����
L%$��J]xy,�T4H	�#w#)��q��'nS��[�w��>STG{o:�Q	]��9_�@C����;E��~(���"l�_	]M��I�@&����������w���p������Nvd�P&o��k!%�=N�s6��	Fs�E��� �4�
l��
6oh}7����a���>tJ���R�c�-��w�m�����-2����_t����*�B����O�?	;f��SVN�3���2��i=��(,$n����J�W��e����
���f���,wSNK�{������G��O���{��Y��V�9xB���m�B�l/\���t<��|&$��n������������c�g��E�����r���J�c��Md���WQ���A��:��g�c��q����+�������K*����"2y.�C����K�`��G*�Q_���d�LX�
�)����`�	-���r#}�Rhn�
��B��<�r�7	B�<>�`t>Zq/�Oa����|,/89�����b��CVy�$@/���{~b)+���~M'�O�3Ln�)��N��m�_w���zRjT���H�l����8���AXX��"	�@@Yx�Mp���t1&�� �����$��(����N�dY��z��A�6z����>���F���:�����*�:q�TC��V��h��YX{Q�P��rO����8~&A���jL��Q��
�K�7NQr��qL��'�%bx<V@D��PA2Y8��/�3�'�9���e��0��nR���V�5�}�0���7��P���ip��DH��9�@9��/��j$s�@yzY��'ig�w���D���]O�{��hr�r���Lk���Z��X_Jf�_D�t=�7 �!�5���=UM� ��Z����_u���+��H��;�1��������<Rt�{��Ju����,N��L���gS$���^�I^bvC�H����
��n��0��Q�)��y�&�(��Sk).���r����-r5�����04�Y�G���}yx�%A�CQ���v�>����v�+����	�V4����$���K��~/k�/��-i���&z���EK�z�F8m���k�
�8�S9�����K��G�~�l��M�+afu3C%�b����XF�T���(�U�� ���62O����������P���W�F������,���J6I�t����&�YYj�Kr33Fl��jo��[�!��.����98o���Wnq���)w%6������pl�:�5���D�((~-H��
~1-)X<c������x�A���5%oj�
�]���w�����p�yG�02�����?lK��Bh!{������%���]�G;���D�����[�s��H��s9��7�
�������:���e2eoA'	o�5��$9���[��q�B_�*)���
k��A#�!;:�8(:��M�BV6LY�����)���.e&��&�<��e�u59�z`V$k$�1�����������Fn���s)Z-���|�<]��K.B�g��h�1�SGj�`*2)�4u�[5MYX~3�&l��k�&b6)&����p��x^��������f�Fsnq�+����K�Uc�i�!��
�����E�0�ZHv�G�����/�gOZI!j�a+
V<O����	-gZ��<9*Ht&i��I(�������
��3!y;h�
sv[��rb��4�oP�e���1Y��;�:�-���y<�DPA�zp���s|�[�����HR=�EC*2/t�����G
T����E���G�9�?w���[�N�S�8�����g���;��5�n��1�{���?�Q:��'zj&�&����"�@��4 /*�M��2WP���h�9r�?����(d��V�
���Z��Er`�~�����Xle
�jLh��ld�N��%;u�������n��D{����kI��5�E�@���B�g�/���y�\����2���a5����t���v�����3�$��M?<�F�\��&��uftw�2�G��7��������f��^����&,Il��O���
4��_����-:D*S(��F���;��3�A7����2�������s�A�ws�Xy��(�:N8������n�YV��J-
�PA�
�9� pRQ���+,���1�`�-���/�{��Uw�;�/0�������S.���BO0�k�������K���u�El�'����c{ZW��R0L��HA��gy�E��+?Sq �B%��w�����
����?�=��)����
��mp���a0����P0H�/�i
�*�=��P�:���9�D?�l�;$VJ�
�v����{L��
�^��$yD������_�g@C[W� 	���yg�������+��=Q�'��F�\����q���tnMF[b�q����|� �?�Y��1n�;0�)�0�{!��jz������\��m���^JDSfC��#<G�����')%��5��I_T~`oB>�c90��j72�?�3�t(lG=�u�I;j�A���j��"i��8Qs���"���KQ��%�y�"��c{��l�+�{�Jg�X
(�k�m����W�gi|����@\w
���2�8.~o]���r':�J�m`\z����|(�A��G���V���%�m+�6������V�4�`��������!v���{��`H'�
_��t�X�"@�x����y%��K
������R�tT[^���cT,���le���J���?/��:9kx�{0�,y���^�e��n��_�3���/������	�*�D��	���&P��zS ������)��	k����b������q�{��>��Y��pS���`8l���z�����U��+!%'��M�4����F���[��(�*���W�5~�u�'��T0��b4GT)�=�q�/��2�����=���y�[����zGG�,{���]9<sU�*�U�VSe�y1Q�c`��X'5S���z��i"Z��a���ENyn�vX�g���a:�#\@E��+$>d��[dc���\+�]1V��,u�U�V/"C��;�������d�������mV�I!ir�������b������I��`7��=��q
1��#�*.������e���'���
U��&����9�d_�A�I�&�,TB���
�;�v����ho��������3L�v����������03�i�����t���2�&'��n�)Z#����b(���7�����"���f�6��7���p�`=�����79��/�de1Y	����V�h��1)���P����V�H��5�*�<��#��7T�1U��$x�'�}��������Z�h����M`-�Z{c�mY�|!��
�P�%�����1�%�`������,��99YS��:
c�5�{3]��������!3�"x�x��yZ�kAz��F�������+*so��Be�e�Yb���I_<x���8h����Kc1�Q���q�C%+qY������ �\�5Z�������=������%?��=�i]/E\#��D�\�1bG���2�tL�:	���6���z�y�e+����fnk�$���tt\���b��.�v:AS�)]�'�Z�	o��*���C\���t��	c��o4���u��%+����
gK9X�V{rT��P �d(.
��4oX����2��Q#���F%���_+ �,e��K����*��� 0�o�����T��@���`y_��`E�9q5U������1u�`L@����Sig3D��N:���}-��a7J��!��1�7�	�!��&���Ud��R�8hrm\���M\r'i������]ee��YJ�p�������M[��V���d)��}"Qg��L��Jh��U�:���4Tu`.�i��tG�>[I;nQJ���tH��z���U��s�iy��b���WeY�1M�P��Z)�9����x����3�rdu��2�Z��������gw=�I�@UQ����r�N���-��kD� �0b�P�&��%Ov�F���)���$�'F��f5��-��_V�X��X���&���?65�F���+)iM��e�Bs�����Qu�
ME�s)}��rn� Q$5�^��NX���#�����T&�����k�:+�\]n�t�m���R���9�}?�����6.f?���Aw2���L�������z>9~���Q1n���*�:Y�3��O� d$b�� �Z�I,j�-�?L�~���m�/23G�j~U��s'~��=����9�t�%���<[Y���Li��v���v}��t1ag�2��)e�b�u(��[	i"�v��mY��01�3�qq-R�D��o�q�T��N9qtABA[�#s��m-���S���B���%��<���jT�j?�R0�����rAtN��L�ebb8�
4nn�T�6[���Q+����i��S/�`>�<2Pl*.C�/1W�XN<6���xx���,����k$�]��d�,�4��J� �E�w��3�k�-�Y�9q2!��n���\�Ksd�MDJ��
�lqq9�er��"����3�P�6�&��~69���|�K}??\yWziB'����#_Do�J�`"y�{���x��e�Ro%���@����Sb'*��K�]a����=We�"pa�R���k,6������3�%�7B��Qo�
K�Y��$+5��:�f���*t����
\?R�J�j�p_X$��6��� X�W
�9�O&y��;$��b���d5�}�i��S�����������P-��Q��z�}������#B9���CE�+��V����a�jT���y���V�~B1��+�.Wh�' ��BR]��*��pt��������e���C�y��
k��C�����G�s$o	E��3��cr��=U�����U��e���^���D��m`�[�K����?~��4�e����,�p$@w�f
0�k��$�"��|XlR'O��Hg���b�l����*S�IL�*u�N�3k<��'#XQ��@*<%���h��M���7GG0Ye�������IM�J����^�{j
���3�,����&�c�Y��{,�.���R�Z�
�[���
W�Y���n{V���+pa�A�����d��8��t?�����q��;3�
�e%�����V���l�?S]���a'�[�DF}6	!�(z�j����y�����-�eD�0{����O!'	��6�I�"�_�}/�:/�ul��<mi]�G������m3w^��4��.L�a����N���aE,�&�B�Vi��Fu����(�A>EW���R��5����:$�/q��mC5� 3��G�Q1�<2�x��@�?����-<�H���f���������������8��{;�MZ�]C;��7]=����1�+�+�0d}���
C� ���i���~`@�	������I�n���i��fV�`h	+Y���A�Q���$��c��n��Z��umB����/F����A�M�����E��,��U���)��o�h�P�!��*&����j�N��Cw���C���>�����=&�����v���R42=5o�E���FQ�vT����9�����UYV��%-�1�]]u�:���2����031�!�F�]��<<�P3��c�~��C�pj��R4gp"u835����x���	LC?�G|�����������C�~t�(
�G
�VL.%��q�EN���0PL]d�����z�9Q���a�
-:�A�e�V�2�#�v��(��#���7�
�gf��&E���.jt���c�-PB�@2��k��t�[H�a�R{�#X�=�t�����Q����P�!\���_MK����o�%�F��.��[����/��+X�k>S@�SM]�)���*^TQ������u��|��<T]�;��:B"��bu�-I������J�)�O���z;�"����k�$�w�d;?�B��05}�];��[��t���6'�����ze0b�K
c���z?/
�E��(�a{��:�>*�p��D�#7����o�DP�T����:����yJA�<��jZ#���m#H��:��5�g`����lR���o� ����m�;�8���
a�Q�=�w����W���~'��0�b�t"�.���:��\�i%S:�ai�u�jY��-�� ���K�`��7d���������/��e��#�`�:�8i8�4jO	��yX'�y5�!�:�����c{%"�a��r�oY�],A�8gF�M��LA^�1'u
N2�p�/N�MsGZ���=�X utz{q�;���X��}r:�L9}����?�H5�������K�
h"�w�xP���������g���|q3�]��8�S�V�E(�D��*��.4H	bH(�[~�3 @J��o��M��O����j[f��H`�R�����T#��K�~�}�cM����"z,!F��-/W�p���9i}cI���`�m�x;''����m��`I{��;d?PZ��W\5%�
�cn!�4dv�%���%���_~�T��1
yB������H����8D��At�	,�
R(�a��
�j� (#d��Q=���@r�f��F�][�5}�p��G���,PrL�2(P�)XA���L,���+�F�N�A�kk�����\1��� ����*
��Mi]�tI�K�T����N�(�m�Cs�0X��������v�1�t�i��O�"����o�R��#C��t���L��*s�y1d�_I����*d	uO(/Z\�wVE��Y�9�+���U�T�!V"�%��0-j�4o�����#g����A}~If����2����k�0���d�CE�Um����(���aF^G�!GT$����1�,[�}-;v������*�21�������z�=������]�(��Z���v�Va7�����UM��~�1���z�I�� H��C���!+�K�S�����kM����9=��4X�����/C��$�k`1!	?����~�4�hU��2ye=
-Q��j�6�D�;dS5���j�uG������8�S�$��R-�q��E�(����6�2&K�i>���S��C��%Dn>4/��eRos�	���v����Z]cV/=�o��Pi��f9=���:������LHg=
�wC�Q���� ���N�<�m2�����(:\�M��������j�Q�� ?`�<m�jc4�BWi�	+�
�uQ�Q���jq���"t�[M/`���!K�I6>}��P�`O~����u� *�JY7��\=���.�F{p�"455{�����3������{�a�����
j�A�����b�x�D�s���^����sCMx��Vr#[�\�aiQe0��N�����!\��H/������\��i�.��E����]@!t��Ar���#��X���\�m�e{����`�	Q�j���9��������^#3mE����C�Z��#��k��T��?x����kYfX�'(����)���l*��}��.��,T��S�	�Wz6'K���W���D��u��38/O��x��k/~���bW2x�eWH,}K������o���5?����m���}��Y�g�w9���f���E�5j�We�����_'�*���/3�F�J���v;zi����by'Z� l�q�a��I���d��Dnu9*��T�i�����"���j�]2�Xt����9A(zP�	7��@��W�0t"C��H}%w�i�}�����`T&�5;�����I+^�nE�C;�"�(Q]�G��?�p��*p�N���������<�@�0]4_w��E�����'7fG��2h��::��2�HR�����v����C�,e�����4�z\`(����|^N=�\�������t�k�����GP��r������S�{2FG��%���p�U�/�Q�0�������>����mk�D]2����Q����:����.�sBX���a�
�T��"$�w�P�a����u����1��a4�(�8~�*V�~�������4
��VZz���t%�[��P5{L��rS�}
�8�!s<N�z�=�.=�6d2*RQQ���\���V��������1YPJwZ�2��43c�C���G�A�v��B��}���{`L&�|���|y����������^9����G�JHv�L�O���3�m��14�\i�������O��I���������	����s��b�s�mfeXX\.�H�w�9=�SrzI�a�(�!��_t��\�S�|Z���1��D��4jb�f����B���u����Hr�
��Y��&4���H��iM��]�Hd�X MO1�P �e���apG�+�S���Dt8O��A'���0a�*��C�"1@�D���!I��+#�x8���X��&%A,2���!&��6�yy�f)�O�H�!TTv2������Km��~���\��3*3={���S&8x0K��( A�����X��[��D@�J�#��OW����{�������7`��j�Q�d��Iy|j�����2x
��c�g��p�$FoU�]���-����@C�KT�0��E��(���Jx��S���ECEB�����*�6�&|M�dz���8z)�S
�H������<-�z*�yh�^�'�1\���]ekd�����1���BJ�M�b����F�������������Wp��.jH"~TM.}
����;�uBuDG3u*8�&4�n��@���`1���'u���Q0����1	�����&5��M��i@�Z�cJ������C
��+s��Z�LP!��U�~~�������}S��+�sJo8����Y��44��nLjG������EV���?
��H���P���3'��L����i��f�t�,�/MJ�-)�2�)ac}^)�>�
�B�#
#6�����I�@)���,J�����*��2��p|ME�$��lx(p���o����[n|����5HA�~c����c��\�mogTm�E��cd�
�O����I(o��GOoN�hS� Nig�0��!EI����a��N#2�k�'�3���a\S�#��V���GkT���VX��C�s}�����H��S�!^VS��#bG�Ow������7��B�*��j�k��tQ~�� �I��I"�C�����w��DjKO��E��D��A4�p���X
��%b��X��&���So��8Kg��A�R�j��RI�>�K
��rC�w������yn?��A��Z7P5X�.o�	�d�Q��F�_.���d2�h� y��������;0^mS�l����C�}@���%#�����b�����AnE��B�����^���+l���I�\���U���P�h;����G!�h�D�1[�����-�tE�����g����"��[k�BQ>�)F��]P�"�������aXh����I�s98�=����)wm��Em$��]iS�h�
(�0 �
2�.�HmE�l�.�c�mu�� �X����n-�H�1��A>zO`^������{y�k����L�Y�A�l�uc���HV
o���P�J����:T��9YX�������W+�{��K���s� 2.v�%�Nb3J
��'��	�kr��3 ���9]��,�+�J�=����H�l��;�n���!�K*�E�R�t����+c�S�;�>�B��.�
����WOQ��.[��N�0,��t�~o:G�tB�4aS#
j@�{-�7���\=��\	�T���I�E]�`r}K�sM��C�B�����������:8�8_���hH
���"Rbq.v��Y�?���4k�)3��"u�W%8�X�k��)�	�$
g��_��j�o��H�2f"�t�
g\���/$z�H���_hV[�������K�F�����DEC*�-�������O��� �Tl@���*I�b�0q�|�m����(z��1��l�,	*X�g�
=^� QA}c�n���~�k�������T�~z�r�c���bT$4��R_��9���L�R��
�����+C
/�y�R��"��
����2�i��I��fS���m�f���3��W��h$��l*�w�yx�_��
�B
&
zH�@nN�wx@�? I���t��0��o���Q�7|S'����+� ����6e��PG�V�
qUb@]���R`��TB�M��?	R�b��\zxzz�}��������V9��e P!����^D����C~?����(8����>���������DW���El��3�ZE&r.a�)o��`c4�6��%�D�MT������v�$>t��GE����]���9��GA����[�*K>�A�����p���i�p��LGE �M?�����R�\�����2
���WT��<�
�MMP�V�	�n�W!@(B!�x���������83f�K��c��X��N�Q�7���uAR�*�$%���V*�a��-�AK^X./U�($�A�p �>��� ���$�����@�M�G(������`�:�S�E�]�C���(�b8�3��bkX�vG��CE��A�w�����������@��;T0b4a�E�)�����f�@D�����#I%%/�p��Y�-�'����T�����M���T*��XM�Td����������Z�f"T�YB��G�-2��P��
�����~�������R1��p<�FE�/�y��� ;0��3]#�m�!<J�t�X���f]sp>t�u��%Igz�rm�mttZG
O�h��J��D�:�d��s�H37Iv��^��Z�*FEcs"t�����V�Y�b9Y���#W$��g �#|�Yl����B8��aE*F��Nr`�� ��7��1����
X��R�T�-ID�������*L$O�������y��Y�X���v������ v��0Xe�6I�^��d2�<�2�Gv��X1;Q4:��Q!<��x��k/���*l�s>������D�6u�`�*�!h+!~Po�����n��4�!O�*5�7���(~����IS������5���:�V[%x� t'��D����q��:N���q��{����" j&T(����C��{=������+R�;�[��@o��(lv�i��������Y�IRu��lT`(�����Ac�7;1�����j�T�������I����hZ�V��*%�Q��fr��8{9n�f�y���+�����HW&���#�`P��������_Q�B������S5T���}fGhb����h�dx�2����[���
j�&�/�z��6_�~�m��|$���m	��_<��d�%s�<����a<���a�Y$����
�>��-�F��Rq�ByE~�v����w�I�A�����T�x6����$�"�RO;>u���Q�\�>�	�y�e�C��.5>�4IK���t�����j��$4���g5|7kGs�^Evl����`GHQ��x�I�����bL������<%O�1��
���p&�9/y2x:��;rSSaP:����O��ST H6����q����ps��O;\*��J��� �B���,��axBZ�
��PA�^$�eP��5���-���A*��*�2qx�T��
S�FH�4�J�8��X�NSD��!�P������c;�7�h���9�t��K�Y�D��eN��g��Nb��9�U���eUG���$cx�nT�mE}:2$�����0�K�
!BRaL�k��?���@��l0=$K=D�hKL�.?�:�Y���;��a�9�s�� `��]U.��4E <����yt(���w��&L����.
*�?eN��3��R��
�h�>g�
P��p=���A��c:8Sd�L7a�=�~�j�!h��������Mp����8�i�d$�HbO%^Rwg:���c��o�~�F��c_/�)�G�F���]P���m�"���B��|*
a�s�><�Cz��[(��:�kvFE��?+BN��mG3�)��;.Q�Zs��^�/���1���?c`��V@�@S�=����:J�5��d������d��	��j�
ax?~!0��
�w�wV
y�;(�`(d#�� ���T��WeY4�N��dou�%05�*N`�kr��2GW4��{=L|��`6:�}W5,ZY��n�
������bT��0~�
rOi��>��6���lG{�c������2@w_��o�	����V����M��n��]N��c���O�I�����#���vo��(�Z���Tj�����@��,,��u���������L�*��.p��E_�_r�&�����Fv&��_�[:�D���M`��m.n�������������C�Tu)VXQ3�BD$��^�l������EC2���p��y�s>A
y���(��2�R���0�Vt1��������E�C�D���by	P��I�h<y��a�p98���Y�'3XF/��j@�B,��z�i���0s��B��NA��#��A��Qu}�9��z�����w���>[��L��H���K����QPq����&�QlV0�I�/���L��M�4�zo���##�f�1���R3�WO}<�S������<�j��x#q�e��<��T������!U���N�hA�a�SyQ+���P�)���k�2����\%���0
VTd>��u����A
��4O�i]&����I[��q�@3�Uw�dA!�������������&����q�(��354#�1O����t�>��`i���;�A��c_������A:�O@�q9�(�u����A����p�zW�-�J��"U~w?�:�]��� ]�#�
�/���XfGvz�n/u��L�����B���tH�!�����s_2��(w������	ZT��!�����8����k��O����x��������P2�::����J�D��:Em�������=�b9��N���zz���J���T�}
~W?�m���S�����x�Z)i{Ean~Mb��0p�DP��M��2��%�>���=}U+���B�s�I��o�����5%@���������0�/Jp��ts>a,{%�����cw;va"�A�EP������vx�04
}���"L�dAq
*N�{��A��1��6�>|��>OJ��`���6_��T�����8T��^*PR�|qKO����a�p��m���05}����'AJ7�����7�gUprUU;X���E�q�0;��M�q<=L�����T���p�~���N��`�<�V9����^�&:��GJkD����l�������j����8`��6 ��x)��@���z3+����������8���T��M�;.�Hh��7�/w"��2��y�l�K�*��A|)\=�F����B���+���e�6�$����l/���"]��d���Q�#�/��M��)�|�}d��O{MsE��z�C
R9���<��~��t{K�X9C�����k��eI���Qb�~T��Jf����p��T$��*�G���x������G���X���@�V�)"4bM�����B@_�!�.���%�~R�$�p�s�T�*T����I�c�|;H�o���P|*���ot'��v��/3Z�T[e�t�V,+�t��F�|]*�:T�����h���]B�fH����
IG��?@�]�e� �j>�����9�t_���k��#}�>/��{�y�F����P1 �H�1����Z8�� ��,���0����4�s'��8}P�B��Q�9'@3%c����^�>NT������������9G)�"���� �g�8���d�eU����.v����){>,&D���)v����O5����0N�2���D�p�;��gS�G�Y-�p������P�(�����y�.�5���y[��Rj��Bzu���PC�V����K���r��Y&C'���z�Z���V9������f-KA��
Uw~�(���Q|8�S��i����av�SA��Bm�V�L0�!���K���J�0m���4'�s����'�_JW`{��.js��.z�I�����^��m��5�A��F���dH�\�8��(nm�}i��-��q�L�#y���A�j����&��]���%�0-.���P��Z��R�i�(���jj����d����N��.d$�E��7x�9�t����i	�SA�����_D����_�MbR+����������H#�SDFz���)��,'��E�'�����7�R�|6�kK);���"?�5$e�����n��v���j�a�o�!�N}��mZ[r���
1��A:� -?`�P���^1�Z��!j_��Z�6����c���3`��E�1���,�d9��'P�s��\� �+h ��=3?L��wj�p� ���\�I&
�Qm	

���i�;����D�a.���/�2������sin�H����)X�J%9��#zX��S98��-�"�����w���y�����'���	�����n��'.�J1���rKb�"���J�GE�@��7�
�p)t��E
�;�����?ut�����8������X��z�|�c!j"SOE����?��N��4�2�;������$������R�o�gM��
��UTCbb���e�u���s���1E�o����4�mF��1����)w���5���8�/��T������((#�<������
�8Z���@+��.�>U������2���$J��%���$e���P���\��4k��0=��Wq@���u{j0)��.���u��mR���VoDw"Pp�5�J}u���"Dd��-��>��!��1���$p�S�
e�P�sC���s�
E�i���L����Z�z+�S"���VB����c��v{g������6=`�u��.Y���=�����:���!1�{)��1�Z-K�]�
B�/�(,L9l\E����g����3���p���W���2��mgc�t��{8�A�gV�pbX�v��r��("�*P�d9�m3�Z=E��+zi,u�V��V�Q�e�'�'��%��}bq�Pe�-W9��l"�U�q�g�2��
�}oJ
r��Xj~�����Y0	�U@�����F1��9\k��k����d�9Do��@N���1{^Kt���QUs��@	��b4��{��]��,��oj/�{):/��
�������/����r�cPk��S��ZH9Po0n
d�����7~Dr����;�(�y��u�y$/��X9����f(e��N��q�*���h�����3�y�6)|P�v�}����t)��v�l:�J�%{"A?�)�B1��0�v ����$k����J�������f�@��'_�x���\��RK���*��O�%��w��Q��z��J��y![�������`�b� ��0�����������R��K(B���������L
��xj:�a��w��I2e*�@����F�[K���������Z>�������A�/�Z���n�dS�(������%;/�KMY���/�z��.�>�A�o��$��U����.<>�9�i���T��1���Q��
$n���*�����F�2�}nh\Ra�i!��%mB�Z?=N\�z :Y#'���!�OB:�����(	�Br6I(7Y�]K^
�����ph�+��r��D�1i�UlE�0w�1���OCo6��:P���k��:��m(���"�;u��B�����R=#!���L���*�
^n@!�%���5�V�?��M��C�-
;������D��s���7�I�ci�P{O� ��0�s���MC�?"��U�(������q��5e���kC4�Z�J���rqZu�|q��R8�;�)�-�t��zi�(����v���#b�/W�1����[$�7N(���+�������x>���Y��+�����e�tq
'��-L��BC~�"J��E�9������T7V\���3��l���*,�����������{��b(��
�4�=�.����.�����",�/���bBZ=�$'QtiC���{��z;:m`:��}yt���F8bc�Q�L3[����S��B��&���jX��@H�	�pR�{�M���&@��UR3�u#�LT�@�Gw���W!*�)'�<c$���iGeD�W��=���\-����J�s�a)��v�K����n���t8����+�X�J���6,���d���E*��F���b�0��3�)��{1)����>�$T/=�R���(���-'�`V\A
��4�6�C�^�Vk�����������K�Y�56]�B|�!�w�/���h��^����j�R(�B]\�����\���i��Yl\x�	o�}�9�U���(����l`���4T[�0�;n������8�]�
�'�I����Er5�z�Q��o���v�u�%�UA^���i���Q9t��[q�sq�%���L�m����RtU��Z�X��Q���*l�;������Y�5����\mj���0��P�{���||�*������P���ZnZF!�E����[UD�I����t�V]C5����P�o�
U9�'��`1�oCZI���_��`k��hu"��Gj�j��A��zu��
�`X����;��K�M�	5Dj�&�.��b�~�t0���%��f���|�x�-������ph#��?Tx���v���j�&��S[r�U9n����T_��P{�;����H�$����0�������6iY��X�X���9o�;Ce�qP$
���aA�|,��[>�T/U1���g�bY�E��T��d�@
$uaPT8�B��f���k���v8��fLp�y�����2�jB�TXP:_�X��6��.I�di=4��~�10��E�P�)/���p
�/9�9>���b�a
s�����`���W7Qx�D��r��N�r���a��qDt�����8�v����XS���'���!J���N�	���� ����xU��m]��)���=��S^��F9T��6����I(��lF~LA����W���RmM��2�PN]���#5l�K;��j���v$��Q�X��#���������<�$���������bx�I�O�;�x
������W����()�
G	Ov�������Y�Rv�6t�������&�{��	y���_�V��e����}�6��ydG8%�^B1�����Q�G��M��>�V�H��
_@Z�J(��[�dk��j�Rx.Gbu���U���Q��s��X��u�OA�%�@�E�MV������K���/>������i|X����6+��W?�m��h����������h�~�{u�|���2����������C=&]X���<��=;	~���?�U�<�����]�r}���Y�����_�}���������)u�N�=�_^}��N:���k�r�����D �gCq�3���b=�������r���������-�|��^����@/���q��mOS����/���������?Q>�>O����g�&����h��W)�W���|*$���$���M���F4�r���hj�*~�������������g>_��"k�f)���,�K��"{���5��s��i�Z���\}��R���|������E�������������8��������l�~�m�GO�Z_Y��e����wy�h,]�<y��wW��������~H��_!��?������/�G�22��q���|&�K�m�.:b��OS?�Y��?��XU����g�F.�)m\�	�����iOG8�������_�_�?�?�?�?�?���������
#107Sumanta Mukherjee
sumanta.mukherjee@enterprisedb.com
In reply to: David Zhang (#106)
Re: WIP/PoC for parallel backup

Hi,

Would it be possible to put in the absolute numbers of the perf
so that it is easier to understand the amount of improvement with
and without the patch and different loads and workers.

I am also unsure why the swapper is taking such a huge percentage of the
absolute time
in the base run of just the postgres server and pg_basebackup client.

With Regards,
Sumanta Mukherjee.
EnterpriseDB: http://www.enterprisedb.com

On Thu, Apr 30, 2020 at 1:18 PM David Zhang <david.zhang@highgo.ca> wrote:

Show quoted text

Hi,

Thanks a lot for sharing the test results. Here is the our test results
using perf on three ASW t2.xlarge with below configuration.

Machine configuration:
Instance Type :t2.xlarge
Volume type :io1
Memory (MiB) :16GB
vCPU # :4
Architecture :x86_64
IOP :6000
Database Size (GB) :45 (Server)

case 1: postgres server: without patch and without load

* Disk I/O:

# Samples: 342K of event 'block:block_rq_insert'
# Event count (approx.): 342834
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. .....................
#
97.65% postgres [kernel.kallsyms] [k] __elv_add_request
2.27% kworker/u30:0 [kernel.kallsyms] [k] __elv_add_request

* CPU:

# Samples: 6M of event 'cpu-clock'
# Event count (approx.): 1559444750000
#
# Overhead Command Shared Object
Symbol
# ........ ............... ....................
.............................................
#
64.73% swapper [kernel.kallsyms] [k] native_safe_halt
10.89% postgres [vdso] [.] __vdso_gettimeofday
5.64% postgres [kernel.kallsyms] [k] do_syscall_64
5.43% postgres libpthread-2.26.so [.] __libc_recv
1.72% postgres [kernel.kallsyms] [k]
pvclock_clocksource_read

* Network:

# Samples: 2M of event 'skb:consume_skb'
# Event count (approx.): 2739785
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. ...........................
#
91.58% swapper [kernel.kallsyms] [k] consume_skb
7.09% postgres [kernel.kallsyms] [k] consume_skb
0.61% kswapd0 [kernel.kallsyms] [k] consume_skb
0.44% ksoftirqd/3 [kernel.kallsyms] [k] consume_skb

case 1: pg_basebackup client: without patch and without load

* Disk I/O:

# Samples: 371K of event 'block:block_rq_insert'
# Event count (approx.): 371362
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. .....................
#
96.78% kworker/u30:0 [kernel.kallsyms] [k] __elv_add_request
2.82% pg_basebackup [kernel.kallsyms] [k] __elv_add_request
0.29% kworker/u30:1 [kernel.kallsyms] [k] __elv_add_request
0.09% xfsaild/xvda1 [kernel.kallsyms] [k] __elv_add_request

* CPU:

# Samples: 3M of event 'cpu-clock'
# Event count (approx.): 903527000000
#
# Overhead Command Shared Object
Symbol
# ........ ............... ..................
.............................................
#
87.99% swapper [kernel.kallsyms] [k] native_safe_halt
3.14% swapper [kernel.kallsyms] [k] __lock_text_start
0.48% swapper [kernel.kallsyms] [k]
__softirqentry_text_start
0.37% pg_basebackup [kernel.kallsyms] [k]
copy_user_enhanced_fast_string
0.35% swapper [kernel.kallsyms] [k] do_csum

* Network:

# Samples: 12M of event 'skb:consume_skb'
# Event count (approx.): 12260713
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. ...........................
#
95.12% swapper [kernel.kallsyms] [k] consume_skb
3.23% pg_basebackup [kernel.kallsyms] [k] consume_skb
0.83% ksoftirqd/1 [kernel.kallsyms] [k] consume_skb
0.45% kswapd0 [kernel.kallsyms] [k] consume_skb

case 2: postgres server: with patch and with load, 4 backup workers on
client side

* Disk I/O:

# Samples: 3M of event 'block:block_rq_insert'
# Event count (approx.): 3634542
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. .....................
#
98.88% postgres [kernel.kallsyms] [k] __elv_add_request
0.66% perf [kernel.kallsyms] [k] __elv_add_request
0.42% kworker/u30:1 [kernel.kallsyms] [k] __elv_add_request
0.01% sshd [kernel.kallsyms] [k] __elv_add_request

* CPU:

# Samples: 9M of event 'cpu-clock'
# Event count (approx.): 2299129250000
#
# Overhead Command Shared Object
Symbol
# ........ ............... .....................
.............................................
#
52.73% swapper [kernel.kallsyms] [k] native_safe_halt
8.31% postgres [vdso] [.] __vdso_gettimeofday
4.46% postgres [kernel.kallsyms] [k] do_syscall_64
4.16% postgres libpthread-2.26.so [.] __libc_recv
1.58% postgres [kernel.kallsyms] [k] __lock_text_start
1.52% postgres [kernel.kallsyms] [k]
pvclock_clocksource_read
0.81% postgres [kernel.kallsyms] [k]
copy_user_enhanced_fast_string

* Network:

# Samples: 6M of event 'skb:consume_skb'
# Event count (approx.): 6048795
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. ...........................
#
85.81% postgres [kernel.kallsyms] [k] consume_skb
12.03% swapper [kernel.kallsyms] [k] consume_skb
0.97% postgres [kernel.kallsyms] [k] __consume_stateless_skb
0.85% ksoftirqd/3 [kernel.kallsyms] [k] consume_skb
0.24% perf [kernel.kallsyms] [k] consume_skb

case 2: pg_basebackup 4 workers: with patch and with load

* Disk I/O:

# Samples: 372K of event 'block:block_rq_insert'
# Event count (approx.): 372360
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. .....................
#
97.26% kworker/u30:0 [kernel.kallsyms] [k] __elv_add_request
1.45% pg_basebackup [kernel.kallsyms] [k] __elv_add_request
0.95% kworker/u30:1 [kernel.kallsyms] [k] __elv_add_request
0.14% xfsaild/xvda1 [kernel.kallsyms] [k] __elv_add_request

* CPU:

# Samples: 4M of event 'cpu-clock'
# Event count (approx.): 1234071000000
#
# Overhead Command Shared Object
Symbol
# ........ ............... ........................
.................................................
#
89.25% swapper [kernel.kallsyms] [k] native_safe_halt
0.93% pg_basebackup [kernel.kallsyms] [k]
__lock_text_start
0.91% swapper [kernel.kallsyms] [k]
__lock_text_start
0.69% pg_basebackup [kernel.kallsyms] [k]
copy_user_enhanced_fast_string
0.45% swapper [kernel.kallsyms] [k] do_csum

* Network:

# Samples: 6M of event 'skb:consume_skb'
# Event count (approx.): 6449013
#
# Overhead Command Shared Object Symbol
# ........ ............... ................. ...........................
#
90.28% pg_basebackup [kernel.kallsyms] [k] consume_skb
9.09% swapper [kernel.kallsyms] [k] consume_skb
0.29% ksoftirqd/1 [kernel.kallsyms] [k] consume_skb
0.21% sshd [kernel.kallsyms] [k] consume_skb

The detailed perf report is attached, with different scenarios, i.e.
without patch (with and without load for server and client) , with patch
(with and without load for 1, 2, 4, 8 workers for both server and client).
The file name should self explain the cases.

Let me know if more information required.

Best regards,

David
On 2020-04-29 5:41 a.m., Suraj Kharage wrote:

Hi,

We at EnterpriseDB did some performance testing around this
parallel backup to check how this is beneficial and below are the results.
In this testing, we run the backup -
1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

*Machine details: *

1: Server (on which local backups performed and used as server for remote
backups)

2: Client (Used as a client for remote backups)

*Server:*
RAM: 500 GB
CPU details:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 8
NUMA node(s): 8
Filesystem: ext4

*Client:*
RAM: 490 GB
CPU details:
Architecture: ppc64le
Byte Order: Little Endian
CPU(s): 192
On-line CPU(s) list: 0-191
Thread(s) per core: 8
Core(s) per socket: 1
Socket(s): 24
Filesystem: ext4

Below are the results for the local test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 0m27.016s
user 0m3.378s
sys 0m23.059s real 0m30.314s
user 0m3.575s
sys 0m22.946s 12% performance
decreased real 0m20.400s
user 0m3.622s
sys 0m29.670s 27% performace
increased real 0m15.331s
user 0m3.706s
sys 0m39.189s 43% performance
increased real 0m15.094s
user 0m3.915s
sys 1m23.350s 44% performace
increased.
50GB
(50 tables - each table around 1.05 GB) real 2m11.049s
user 0m16.464s
sys 2m1.757s real 2m26.621s
user 0m18.497s
sys 2m4.792s 21% performance
decreased real 1m9.581s
user 0m18.298s
sys 2m12.030s 46% performance
increased real 0m53.894s
user 0m18.588s
sys 2m47.390s 58% performance
increased. real 0m55.373s
user 0m18.423s
sys 5m57.470s 57% performance
increased.
100GB
(100 tables - each table around 1.05 GB) real 4m4.776s
user 0m33.699s
sys 3m27.777s real 4m20.862s
user 0m35.753s
sys 3m28.262s 6% performance
decreased real 2m37.411s
user 0m36.440s
sys 4m16.424s" 35% performance
increased real 1m49.503s
user 0m37.200s
sys 5m58.077s 55% performace
increased real 1m36.762s
user 0m36.987s
sys 9m36.906s 60% performace
increased.
200GB
(200 tables - each table around 1.05 GB) real 10m34.998s
user 1m8.471s
sys 7m21.520s real 11m30.899s
user 1m12.933s
sys 8m14.496s 8% performance
decreased real 6m8.481s
user 1m13.771s
sys 9m31.216s 41% performance
increased real 4m2.403s
user 1m18.331s
sys 12m29.661s 61% performance
increased real 4m3.768s
user 1m24.547s
sys 15m21.421s 61% performance
increased

Results for the remote test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 1m36.829s
user 0m2.124s
sys 0m14.004s real 1m37.598s
user 0m3.272s
sys 0m11.110s 0.8% performance
decreased real 1m36.753s
user 0m2.627s
sys 0m15.312s 0.08% performance
increased. real 1m37.212s
user 0m3.835s
sys 0m13.221s 0.3% performance
decreased. real 1m36.977s
user 0m4.475s
sys 0m17.937s 0.1% perfomance
decreased.
50GB
(50 tables - each table around 1.05 GB) real 7m54.211s
user 0m10.826s
sys 1m10.435s real 7m55.603s
user 0m16.535s
sys 1m8.147s 0.2% performance
decreased real 7m53.499s
user 0m18.131s
sys 1m8.822s 0.1% performance
increased. real 7m54.687s
user 0m15.818s
sys 1m30.991s 0.1% performance
decreased real 7m54.658s
user 0m20.783s
sys 1m34.460s 0.1% performance
decreased
100GB
(100 tables - each table around 1.05 GB) real 15m45.776s
user 0m21.802s
sys 2m59.006s real 15m46.315s
user 0m32.499s
sys 2m47.245s 0.05% performance
decreased real 15m46.065s
user 0m28.877s
sys 2m21.181s 0.03% performacne
drcreased real 15m47.793s
user 0m30.932s
sys 2m36.708s 0.2% performance
decresed real 15m47.129s
user 0m35.151s
sys 3m23.572s 0.14% performance
decreased.
200GB
(200 tables - each table around 1.05 GB) real 32m55.720s
user 0m50.602s
sys 5m38.875s real 31m30.602s
user 0m45.377s
sys 4m57.405s 4% performance
increased real 31m30.214s
user 0m55.023s
sys 5m8.689s 4% performance
increased real 31m31.187s
user 1m13.390s
sys 5m40.861s 4% performance
increased real 31m31.729s
user 1m4.955s
sys 6m35.774s 4% performance
decreased

Client & Server on the same machine, the result shows around 50%
improvement in parallel run with worker 4 and 8. We don’t see the huge
performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t see
any major benefit in performance. This testing result matches the testing
results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU
usage and other information. What we noticed is that server is consuming
the CPU almost 100% whole the time and pg_stat_activity shows that server
is busy with ClientWrite most of the time.

Attaching captured output for

1) Top command output on the server after every 5 second

2) pg_stat_activity output after every 5 second

3) Top command output on the client after every 5 second

Do let me know if anyone has further questions/inputs for the
benchmarking.

Thanks to Rushabh Lathia for helping me with this testing.

On Tue, Apr 28, 2020 at 8:46 AM Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Mon, Apr 27, 2020 at 10:23 PM David Zhang <david.zhang@highgo.ca>
wrote:

Hi,

Here is the parallel backup performance test results with and without
the patch "parallel_backup_v15" on AWS cloud environment. Two
"t2.xlarge" machines were used: one for Postgres server and the other
one for pg_basebackup with the same machine configuration showing below.

Machine configuration:
Instance Type :t2.xlarge
Volume type :io1
Memory (MiB) :16GB
vCPU # :4
Architecture :x86_64
IOP :6000
Database Size (GB) :108

Performance test results:
without patch:
real 18m49.346s
user 1m24.178s
sys 7m2.966s

1 worker with patch:
real 18m43.201s
user 1m55.787s
sys 7m24.724s

2 worker with patch:
real 18m47.373s
user 2m22.970s
sys 11m23.891s

4 worker with patch:
real 18m46.878s
user 2m26.791s
sys 13m14.716s

As required, I didn't have the pgbench running in parallel like we did
in the previous benchmark.

So, there doesn't seem to be any significant improvement in this
scenario. Now, it is not clear why there was a significant
improvement in the previous run where pgbench was also running
simultaneously. I am not sure but maybe it is because when a lot of
other backends were running (performing read-only workload) the
backend that was responsible for doing backup was getting frequently
scheduled out and it slowed down the overall backup process. And when
we start using multiple backends for backup one or other backup
process is always running making the overall backup faster. One idea
to find this out is to check how much time backup takes when we run it
with and without pgbench workload on HEAD (aka unpatched code). Even
if what I am saying is true or there is some other reason due to which
we are seeing speedup in some cases (where there is a concurrent
workload), it might not make the case for using multiple backends for
backup but still, it is good to find that information as it might help
in designing this feature better.

The perf report files for both Postgres server and pg_basebackup sides
are attached.

It is not clear which functions are taking more time or for which
functions time is reduced as function symbols are not present in the
reports. I think you can refer
"https://wiki.postgresql.org/wiki/Profiling_with_perf&quot; to see how to
take profiles and additionally use -fno-omit-frame-pointer during
configure (you can use CFLAGS="-fno-omit-frame-pointer during
configure).

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
--

Thanks & Regards,
Suraj kharage,
EnterpriseDB Corporation,
The Postgres Database Company.

--
David

Software Engineer
Highgo Software Inc. (Canada)
www.highgo.ca

#108Amit Kapila
amit.kapila16@gmail.com
In reply to: Suraj Kharage (#105)
Re: WIP/PoC for parallel backup

On Wed, Apr 29, 2020 at 6:11 PM Suraj Kharage
<suraj.kharage@enterprisedb.com> wrote:

Hi,

We at EnterpriseDB did some performance testing around this parallel backup to check how this is beneficial and below are the results. In this testing, we run the backup -
1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

Machine details:

1: Server (on which local backups performed and used as server for remote backups)

2: Client (Used as a client for remote backups)

...

Client & Server on the same machine, the result shows around 50% improvement in parallel run with worker 4 and 8. We don’t see the huge performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t see any major benefit in performance. This testing result matches the testing results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU usage and other information. What we noticed is that server is consuming the CPU almost 100% whole the time and pg_stat_activity shows that server is busy with ClientWrite most of the time.

Was this for a setup where the client and server were on the same
machine or where the client was on a different machine? If it was for
the case where both are on the same machine, then ideally, we should
see ClientRead events in a similar proportion?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#109Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#108)
Re: WIP/PoC for parallel backup

On Thu, Apr 30, 2020 at 4:15 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Apr 29, 2020 at 6:11 PM Suraj Kharage
<suraj.kharage@enterprisedb.com> wrote:

Hi,

We at EnterpriseDB did some performance testing around this parallel backup to check how this is beneficial and below are the results. In this testing, we run the backup -
1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

Machine details:

1: Server (on which local backups performed and used as server for remote backups)

2: Client (Used as a client for remote backups)

...

Client & Server on the same machine, the result shows around 50% improvement in parallel run with worker 4 and 8. We don’t see the huge performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t see any major benefit in performance. This testing result matches the testing results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU usage and other information. What we noticed is that server is consuming the CPU almost 100% whole the time and pg_stat_activity shows that server is busy with ClientWrite most of the time.

Was this for a setup where the client and server were on the same
machine or where the client was on a different machine? If it was for
the case where both are on the same machine, then ideally, we should
see ClientRead events in a similar proportion?

During an offlist discussion with Robert, he pointed out that current
basebackup's code doesn't account for the wait event for the reading
of files which can change what pg_stat_activity shows? Can you please
apply his latest patch to improve basebackup.c's code [1]/messages/by-id/CA+TgmobBw-3573vMosGj06r72ajHsYeKtksT_oTxH8XvTL7DxA@mail.gmail.com which will
take care of that waitevent before getting the data again?

[1]: /messages/by-id/CA+TgmobBw-3573vMosGj06r72ajHsYeKtksT_oTxH8XvTL7DxA@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#110David Zhang
david.zhang@highgo.ca
In reply to: Sumanta Mukherjee (#107)
Re: WIP/PoC for parallel backup

On 2020-04-30 2:18 a.m., Sumanta Mukherjee wrote:

Hi,

Would it be possible to put in the absolute numbers of the perf
so that it is easier to understand the amount of improvement with
and without the patch and different loads and workers.

Here is the parameters used to record the perf data on both server and
client side, for example, after applied the patch15 using 4 workers with
load,

perf record -o postgres_patch_j4_load -e block:block_rq_insert -e
cpu-clock -e cycles:k -e skb:consume_skb -aR -s --
/home/ec2-user/after/bin/postgres -D /mnt/test/data

perf record -o backup_patch_j4_load -e block:block_rq_insert -e
cpu-clock -e cycles:k -e skb:consume_skb -aR -s --
/home/ec2-user/after/bin/pg_basebackup -h ${PG_SERVER} -p 5432 -D
/mnt/backup/data -v

And this is how the report is generated.
perf report  -i postgres_patch_j4_load --stdio > postgres_patch_j4_load.txt

The original perf data files are still available, can you please clarify
which parameter you would like to be added for regenerating the report,
or any other parameters need to be added to recreate the perf.data and
then generate the report?

I am also unsure why the swapper is taking such a huge percentage of
the absolute time
in the base run of just the postgres server and pg_basebackup client.

With Regards,
Sumanta Mukherjee.
EnterpriseDB: http://www.enterprisedb.com

On Thu, Apr 30, 2020 at 1:18 PM David Zhang <david.zhang@highgo.ca
<mailto:david.zhang@highgo.ca>> wrote:

Hi,

Thanks a lot for sharing the test results. Here is the our test
results using perf on three ASW t2.xlarge with below configuration.

Machine configuration:
      Instance Type        :t2.xlarge
      Volume type          :io1
      Memory (MiB)         :16GB
      vCPU #                   :4
      Architecture           :x86_64
      IOP                         :6000
      Database Size (GB)  :45 (Server)

case 1: postgres server: without patch and without load

* Disk I/O:

# Samples: 342K of event 'block:block_rq_insert'
# Event count (approx.): 342834
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    97.65%  postgres         [kernel.kallsyms]  [k] __elv_add_request
     2.27%  kworker/u30:0    [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 6M of event 'cpu-clock'
# Event count (approx.): 1559444750000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ....................
.............................................
#
    64.73%  swapper          [kernel.kallsyms]     [k]
native_safe_halt
    10.89%  postgres         [vdso]                [.]
__vdso_gettimeofday
     5.64%  postgres         [kernel.kallsyms]     [k] do_syscall_64
     5.43%  postgres libpthread-2.26.so
<http://libpthread-2.26.so&gt;    [.] __libc_recv
     1.72%  postgres         [kernel.kallsyms]     [k]
pvclock_clocksource_read

* Network:

# Samples: 2M of event 'skb:consume_skb'
# Event count (approx.): 2739785
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  .................
...........................
#
    91.58%  swapper          [kernel.kallsyms]  [k] consume_skb
     7.09%  postgres         [kernel.kallsyms]  [k] consume_skb
     0.61%  kswapd0          [kernel.kallsyms]  [k] consume_skb
     0.44%  ksoftirqd/3      [kernel.kallsyms]  [k] consume_skb

case 1: pg_basebackup client: without patch and without load

* Disk I/O:

# Samples: 371K of event 'block:block_rq_insert'
# Event count (approx.): 371362
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    96.78%  kworker/u30:0    [kernel.kallsyms]  [k] __elv_add_request
     2.82%  pg_basebackup    [kernel.kallsyms]  [k] __elv_add_request
     0.29%  kworker/u30:1    [kernel.kallsyms]  [k] __elv_add_request
     0.09%  xfsaild/xvda1    [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 3M of event 'cpu-clock'
# Event count (approx.): 903527000000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ..................
.............................................
#
    87.99%  swapper          [kernel.kallsyms]   [k] native_safe_halt
     3.14%  swapper          [kernel.kallsyms]   [k] __lock_text_start
     0.48%  swapper          [kernel.kallsyms]   [k]
__softirqentry_text_start
     0.37%  pg_basebackup    [kernel.kallsyms]   [k]
copy_user_enhanced_fast_string
     0.35%  swapper          [kernel.kallsyms]   [k] do_csum

* Network:

# Samples: 12M of event 'skb:consume_skb'
# Event count (approx.): 12260713
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  .................
...........................
#
    95.12%  swapper          [kernel.kallsyms]  [k] consume_skb
     3.23%  pg_basebackup    [kernel.kallsyms]  [k] consume_skb
     0.83%  ksoftirqd/1      [kernel.kallsyms]  [k] consume_skb
     0.45%  kswapd0          [kernel.kallsyms]  [k] consume_skb

case 2: postgres server: with patch and with load, 4 backup
workers on client side

* Disk I/O:

# Samples: 3M of event 'block:block_rq_insert'
# Event count (approx.): 3634542
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    98.88%  postgres         [kernel.kallsyms]  [k] __elv_add_request
     0.66%  perf             [kernel.kallsyms]  [k] __elv_add_request
     0.42%  kworker/u30:1    [kernel.kallsyms]  [k] __elv_add_request
     0.01%  sshd             [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 9M of event 'cpu-clock'
# Event count (approx.): 2299129250000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  .....................
.............................................
#
    52.73%  swapper          [kernel.kallsyms]      [k]
native_safe_halt
     8.31%  postgres         [vdso]                 [.]
__vdso_gettimeofday
     4.46%  postgres         [kernel.kallsyms]      [k] do_syscall_64
     4.16%  postgres libpthread-2.26.so
<http://libpthread-2.26.so&gt;     [.] __libc_recv
     1.58%  postgres         [kernel.kallsyms]      [k]
__lock_text_start
     1.52%  postgres         [kernel.kallsyms]      [k]
pvclock_clocksource_read
     0.81%  postgres         [kernel.kallsyms]      [k]
copy_user_enhanced_fast_string

* Network:

# Samples: 6M of event 'skb:consume_skb'
# Event count (approx.): 6048795
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  .................
...........................
#
    85.81%  postgres         [kernel.kallsyms]  [k] consume_skb
    12.03%  swapper          [kernel.kallsyms]  [k] consume_skb
     0.97%  postgres         [kernel.kallsyms]  [k]
__consume_stateless_skb
     0.85%  ksoftirqd/3      [kernel.kallsyms]  [k] consume_skb
     0.24%  perf             [kernel.kallsyms]  [k] consume_skb

case 2: pg_basebackup 4 workers: with patch and with load

* Disk I/O:

# Samples: 372K of event 'block:block_rq_insert'
# Event count (approx.): 372360
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ................. .....................
#
    97.26%  kworker/u30:0    [kernel.kallsyms]  [k] __elv_add_request
     1.45%  pg_basebackup    [kernel.kallsyms]  [k] __elv_add_request
     0.95%  kworker/u30:1    [kernel.kallsyms]  [k] __elv_add_request
     0.14%  xfsaild/xvda1    [kernel.kallsyms]  [k] __elv_add_request

* CPU:

# Samples: 4M of event 'cpu-clock'
# Event count (approx.): 1234071000000
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  ........................
.................................................
#
    89.25%  swapper          [kernel.kallsyms] [k] native_safe_halt
     0.93%  pg_basebackup    [kernel.kallsyms] [k] __lock_text_start
     0.91%  swapper          [kernel.kallsyms] [k] __lock_text_start
     0.69%  pg_basebackup    [kernel.kallsyms] [k]
copy_user_enhanced_fast_string
     0.45%  swapper          [kernel.kallsyms] [k] do_csum

* Network:

# Samples: 6M of event 'skb:consume_skb'
# Event count (approx.): 6449013
#
# Overhead  Command          Shared Object Symbol
# ........  ...............  .................
...........................
#
    90.28%  pg_basebackup    [kernel.kallsyms]  [k] consume_skb
     9.09%  swapper          [kernel.kallsyms]  [k] consume_skb
     0.29%  ksoftirqd/1      [kernel.kallsyms]  [k] consume_skb
     0.21%  sshd             [kernel.kallsyms]  [k] consume_skb

The detailed perf report is attached, with different scenarios,
i.e. without patch (with and without load for server and client) ,
with patch (with and without load for 1, 2, 4, 8 workers for both
server and client). The file name should self explain the cases.

Let me know if more information required.

Best regards,

David

On 2020-04-29 5:41 a.m., Suraj Kharage wrote:

Hi,

We at EnterpriseDB did some performance testing around this
parallel backup to check how this is beneficial and below are the
results. In this testing, we run the backup -
1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

*Machine details: *

1: Server (on which local backups performed and used as server
for remote backups)

2: Client (Used as a client for remote backups)

*Server:*

RAM:500 GB
CPU details:
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 8
Socket(s): 8
NUMA node(s): 8
Filesystem:ext4

*Client:*
RAM:490 GB
CPU details:
Architecture: ppc64le
Byte Order: Little Endian
CPU(s): 192
On-line CPU(s) list: 0-191
Thread(s) per core: 8
Core(s) per socket: 1
Socket(s): 24
Filesystem:ext4

Below are the results for the local test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 0m27.016s
user 0m3.378s
sys 0m23.059s real 0m30.314s
user 0m3.575s
sys 0m22.946s 12% performance
decreased real 0m20.400s
user 0m3.622s
sys 0m29.670s 27% performace
increased real 0m15.331s
user 0m3.706s
sys 0m39.189s 43% performance
increased real 0m15.094s
user 0m3.915s
sys 1m23.350s 44% performace
increased.
50GB
(50 tables - each table around 1.05 GB) real 2m11.049s
user 0m16.464s
sys 2m1.757s real 2m26.621s
user 0m18.497s
sys 2m4.792s 21% performance
decreased real 1m9.581s
user 0m18.298s
sys 2m12.030s 46% performance
increased real 0m53.894s
user 0m18.588s
sys 2m47.390s 58% performance
increased. real 0m55.373s
user 0m18.423s
sys 5m57.470s 57% performance
increased.
100GB
(100 tables - each table around 1.05 GB) real 4m4.776s
user 0m33.699s
sys 3m27.777s real 4m20.862s
user 0m35.753s
sys 3m28.262s 6% performance
decreased real 2m37.411s
user 0m36.440s
sys 4m16.424s" 35% performance
increased real 1m49.503s
user 0m37.200s
sys 5m58.077s 55% performace
increased real 1m36.762s
user 0m36.987s
sys 9m36.906s 60% performace
increased.
200GB
(200 tables - each table around 1.05 GB) real 10m34.998s
user 1m8.471s
sys 7m21.520s real 11m30.899s
user 1m12.933s
sys 8m14.496s 8% performance
decreased real 6m8.481s
user 1m13.771s
sys 9m31.216s 41% performance
increased real 4m2.403s
user 1m18.331s
sys 12m29.661s 61% performance
increased real 4m3.768s
user 1m24.547s
sys 15m21.421s 61% performance
increased

Results for the remote test:

Data size without paralle backup
patch parallel backup with
1 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
2 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
4 worker % performance
increased/decreased
compare to normal
backup
(without patch) parallel backup with
8 worker % performance
increased/decreased
compare to normal
backup
(without patch)
10 GB
(10 tables - each table around 1.05 GB) real 1m36.829s
user 0m2.124s
sys 0m14.004s real 1m37.598s
user 0m3.272s
sys 0m11.110s 0.8% performance
decreased real 1m36.753s
user 0m2.627s
sys 0m15.312s 0.08% performance
increased. real 1m37.212s
user 0m3.835s
sys 0m13.221s 0.3% performance
decreased. real 1m36.977s
user 0m4.475s
sys 0m17.937s 0.1% perfomance
decreased.
50GB
(50 tables - each table around 1.05 GB) real 7m54.211s
user 0m10.826s
sys 1m10.435s real 7m55.603s
user 0m16.535s
sys 1m8.147s 0.2% performance
decreased real 7m53.499s
user 0m18.131s
sys 1m8.822s 0.1% performance
increased. real 7m54.687s
user 0m15.818s
sys 1m30.991s 0.1% performance
decreased real 7m54.658s
user 0m20.783s
sys 1m34.460s 0.1% performance
decreased
100GB
(100 tables - each table around 1.05 GB) real 15m45.776s
user 0m21.802s
sys 2m59.006s real 15m46.315s
user 0m32.499s
sys 2m47.245s 0.05% performance
decreased real 15m46.065s
user 0m28.877s
sys 2m21.181s 0.03% performacne
drcreased real 15m47.793s
user 0m30.932s
sys 2m36.708s 0.2% performance
decresed real 15m47.129s
user 0m35.151s
sys 3m23.572s 0.14% performance
decreased.
200GB
(200 tables - each table around 1.05 GB) real 32m55.720s
user 0m50.602s
sys 5m38.875s real 31m30.602s
user 0m45.377s
sys 4m57.405s 4% performance
increased real 31m30.214s
user 0m55.023s
sys 5m8.689s 4% performance
increased real 31m31.187s
user 1m13.390s
sys 5m40.861s 4% performance
increased real 31m31.729s
user 1m4.955s
sys 6m35.774s 4% performance
decreased

Client & Server on the same machine, the result shows around 50%
improvement in parallel run with worker 4 and 8.  We don’t see
the huge performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we
don’t see any major benefit in performance.  This testing result
matches the testing results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see
the CPU usage and other information. What we noticed is that
server is consuming the CPU almost 100% whole the time and
pg_stat_activity shows that server is busy with ClientWrite most
of the time.

Attaching captured output for

1) Top command output on the server after every 5 second

2) pg_stat_activity output after every 5 second

3) Top command output on the client after every 5 second

Do let me know if anyone has further questions/inputs for the
benchmarking.

Thanks to Rushabh Lathia for helping me with this testing.

On Tue, Apr 28, 2020 at 8:46 AM Amit Kapila
<amit.kapila16@gmail.com <mailto:amit.kapila16@gmail.com>> wrote:

On Mon, Apr 27, 2020 at 10:23 PM David Zhang
<david.zhang@highgo.ca <mailto:david.zhang@highgo.ca>> wrote:

Hi,

Here is the parallel backup performance test results with

and without

the patch "parallel_backup_v15" on AWS cloud environment. Two
"t2.xlarge" machines were used: one for Postgres server and

the other

one for pg_basebackup with the same machine configuration

showing below.

Machine configuration:
      Instance Type        :t2.xlarge
      Volume type          :io1
      Memory (MiB)         :16GB
      vCPU #               :4
      Architecture         :x86_64
      IOP                  :6000
      Database Size (GB)   :108

Performance test results:
without patch:
      real 18m49.346s
      user 1m24.178s
      sys 7m2.966s

1 worker with patch:
      real 18m43.201s
      user 1m55.787s
      sys 7m24.724s

2 worker with patch:
      real 18m47.373s
      user 2m22.970s
      sys 11m23.891s

4 worker with patch:
      real 18m46.878s
      user 2m26.791s
      sys 13m14.716s

As required, I didn't have the pgbench running in parallel

like we did

in the previous benchmark.

So, there doesn't seem to be any significant improvement in this
scenario.  Now, it is not clear why there was a significant
improvement in the previous run where pgbench was also running
simultaneously.  I am not sure but maybe it is because when a
lot of
other backends were running (performing read-only workload) the
backend that was responsible for doing backup was getting
frequently
scheduled out and it slowed down the overall backup process. 
And when
we start using multiple backends for backup one or other backup
process is always running making the overall backup faster. 
One idea
to find this out is to check how much time backup takes when
we run it
with and without pgbench workload on HEAD (aka unpatched
code).  Even
if what I am saying is true or there is some other reason due
to which
we are seeing speedup in some cases (where there is a concurrent
workload), it might not make the case for using multiple
backends for
backup but still, it is good to find that information as it
might help
in designing this feature better.

The perf report files for both Postgres server and

pg_basebackup sides

are attached.

It is not clear which functions are taking more time or for which
functions time is reduced as function symbols are not present
in the
reports.  I think you can refer
"https://wiki.postgresql.org/wiki/Profiling_with_perf&quot; to see
how to
take profiles and additionally use -fno-omit-frame-pointer during
configure (you can use CFLAGS="-fno-omit-frame-pointer during
configure).

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
--

Thanks & Regards,
Suraj kharage,
EnterpriseDB Corporation,
The Postgres Database Company.

--
David

Software Engineer
Highgo Software Inc. (Canada)
www.highgo.ca <http://www.highgo.ca&gt;

--
David

Software Engineer
Highgo Software Inc. (Canada)
www.highgo.ca

#111Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Amit Kapila (#108)
Re: WIP/PoC for parallel backup

On Thu, Apr 30, 2020 at 4:15 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Apr 29, 2020 at 6:11 PM Suraj Kharage
<suraj.kharage@enterprisedb.com> wrote:

Hi,

We at EnterpriseDB did some performance testing around this parallel

backup to check how this is beneficial and below are the results. In this
testing, we run the backup -

1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

Machine details:

1: Server (on which local backups performed and used as server for

remote backups)

2: Client (Used as a client for remote backups)

...

Client & Server on the same machine, the result shows around 50%

improvement in parallel run with worker 4 and 8. We don’t see the huge
performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t see

any major benefit in performance. This testing result matches the testing
results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU

usage and other information. What we noticed is that server is consuming
the CPU almost 100% whole the time and pg_stat_activity shows that server
is busy with ClientWrite most of the time.

Was this for a setup where the client and server were on the same
machine or where the client was on a different machine? If it was for
the case where both are on the same machine, then ideally, we should
see ClientRead events in a similar proportion?

In the particular setup, the client and server were on different machines.

During an offlist discussion with Robert, he pointed out that current
basebackup's code doesn't account for the wait event for the reading
of files which can change what pg_stat_activity shows? Can you please
apply his latest patch to improve basebackup.c's code [1] which will
take care of that waitevent before getting the data again?

[1] -
/messages/by-id/CA+TgmobBw-3573vMosGj06r72ajHsYeKtksT_oTxH8XvTL7DxA@mail.gmail.com

Sure, we can try out this and do a similar run to collect the
pg_stat_activity output.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Rushabh Lathia

#112Ahsan Hadi
ahsan.hadi@gmail.com
In reply to: Rushabh Lathia (#111)
Re: WIP/PoC for parallel backup

On Mon, May 4, 2020 at 6:22 PM Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

On Thu, Apr 30, 2020 at 4:15 PM Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Wed, Apr 29, 2020 at 6:11 PM Suraj Kharage
<suraj.kharage@enterprisedb.com> wrote:

Hi,

We at EnterpriseDB did some performance testing around this parallel

backup to check how this is beneficial and below are the results. In this
testing, we run the backup -

1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

Machine details:

1: Server (on which local backups performed and used as server for

remote backups)

2: Client (Used as a client for remote backups)

...

Client & Server on the same machine, the result shows around 50%

improvement in parallel run with worker 4 and 8. We don’t see the huge
performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t

see any major benefit in performance. This testing result matches the
testing results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU

usage and other information. What we noticed is that server is consuming
the CPU almost 100% whole the time and pg_stat_activity shows that server
is busy with ClientWrite most of the time.

Was this for a setup where the client and server were on the same
machine or where the client was on a different machine? If it was for
the case where both are on the same machine, then ideally, we should
see ClientRead events in a similar proportion?

In the particular setup, the client and server were on different machines.

During an offlist discussion with Robert, he pointed out that current
basebackup's code doesn't account for the wait event for the reading
of files which can change what pg_stat_activity shows? Can you please
apply his latest patch to improve basebackup.c's code [1] which will
take care of that waitevent before getting the data again?

[1] -
/messages/by-id/CA+TgmobBw-3573vMosGj06r72ajHsYeKtksT_oTxH8XvTL7DxA@mail.gmail.com

Sure, we can try out this and do a similar run to collect the
pg_stat_activity output.

Have you had the chance to try this out?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Rushabh Lathia

--
Highgo Software (Canada/China/Pakistan)
URL : http://www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
EMAIL: mailto: ahsan.hadi@highgo.ca

#113Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Ahsan Hadi (#112)
2 attachment(s)
Re: WIP/PoC for parallel backup

On Thu, May 21, 2020 at 10:47 AM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

On Mon, May 4, 2020 at 6:22 PM Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

On Thu, Apr 30, 2020 at 4:15 PM Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Wed, Apr 29, 2020 at 6:11 PM Suraj Kharage
<suraj.kharage@enterprisedb.com> wrote:

Hi,

We at EnterpriseDB did some performance testing around this parallel

backup to check how this is beneficial and below are the results. In this
testing, we run the backup -

1) Without Asif’s patch
2) With Asif’s patch and combination of workers 1,2,4,8.

We run those test on two setup

1) Client and Server both on the same machine (Local backups)

2) Client and server on a different machine (remote backups)

Machine details:

1: Server (on which local backups performed and used as server for

remote backups)

2: Client (Used as a client for remote backups)

...

Client & Server on the same machine, the result shows around 50%

improvement in parallel run with worker 4 and 8. We don’t see the huge
performance improvement with more workers been added.

Whereas, when the client and server on a different machine, we don’t

see any major benefit in performance. This testing result matches the
testing results posted by David Zhang up thread.

We ran the test for 100GB backup with parallel worker 4 to see the CPU

usage and other information. What we noticed is that server is consuming
the CPU almost 100% whole the time and pg_stat_activity shows that server
is busy with ClientWrite most of the time.

Was this for a setup where the client and server were on the same
machine or where the client was on a different machine? If it was for
the case where both are on the same machine, then ideally, we should
see ClientRead events in a similar proportion?

In the particular setup, the client and server were on different
machines.

During an offlist discussion with Robert, he pointed out that current
basebackup's code doesn't account for the wait event for the reading
of files which can change what pg_stat_activity shows? Can you please
apply his latest patch to improve basebackup.c's code [1] which will
take care of that waitevent before getting the data again?

[1] -
/messages/by-id/CA+TgmobBw-3573vMosGj06r72ajHsYeKtksT_oTxH8XvTL7DxA@mail.gmail.com

Sure, we can try out this and do a similar run to collect the
pg_stat_activity output.

Have you had the chance to try this out?

Yes. My colleague Suraj tried this and here are the pg_stat_activity output
files.

Captured wait events after every 3 seconds during the backup for -
1: parallel backup for 100GB data with 4 workers
(pg_stat_activity_normal_backup_100GB.txt)
2: Normal backup (without parallel backup patch) for 100GB data
(pg_stat_activity_j4_100GB.txt)

Here is the observation:

The total number of events (pg_stat_activity) captured during above runs:
- 314 events for normal backups
- 316 events for parallel backups (-j 4)

BaseBackupRead wait event numbers: (newly added)
37 - in normal backups
25 - in the parallel backup (-j 4)

ClientWrite wait event numbers:
175 - in normal backup
1098 - in parallel backups

ClientRead wait event numbers:
0 - ClientRead in normal backup
326 - ClientRead in parallel backups for diff processes. (all in idle state)

Thanks,
Rushabh Lathia
www.EnterpriseDB.com

Attachments:

pg_stat_activity_j4_100GB.txttext/plain; charset=US-ASCII; name=pg_stat_activity_j4_100GB.txtDownload
pg_stat_activity_normal_backup_100GB.txttext/plain; charset=US-ASCII; name=pg_stat_activity_normal_backup_100GB.txtDownload
#114Amit Kapila
amit.kapila16@gmail.com
In reply to: Rushabh Lathia (#113)
Re: WIP/PoC for parallel backup

On Thu, May 21, 2020 at 11:36 AM Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

On Thu, May 21, 2020 at 10:47 AM Ahsan Hadi <ahsan.hadi@gmail.com> wrote:

During an offlist discussion with Robert, he pointed out that current
basebackup's code doesn't account for the wait event for the reading
of files which can change what pg_stat_activity shows? Can you please
apply his latest patch to improve basebackup.c's code [1] which will
take care of that waitevent before getting the data again?

[1] - /messages/by-id/CA+TgmobBw-3573vMosGj06r72ajHsYeKtksT_oTxH8XvTL7DxA@mail.gmail.com

Sure, we can try out this and do a similar run to collect the pg_stat_activity output.

Have you had the chance to try this out?

Yes. My colleague Suraj tried this and here are the pg_stat_activity output files.

Captured wait events after every 3 seconds during the backup for -
1: parallel backup for 100GB data with 4 workers (pg_stat_activity_normal_backup_100GB.txt)
2: Normal backup (without parallel backup patch) for 100GB data (pg_stat_activity_j4_100GB.txt)

Here is the observation:

The total number of events (pg_stat_activity) captured during above runs:
- 314 events for normal backups
- 316 events for parallel backups (-j 4)

BaseBackupRead wait event numbers: (newly added)
37 - in normal backups
25 - in the parallel backup (-j 4)

ClientWrite wait event numbers:
175 - in normal backup
1098 - in parallel backups

ClientRead wait event numbers:
0 - ClientRead in normal backup
326 - ClientRead in parallel backups for diff processes. (all in idle state)

It might be interesting to see why ClientRead/ClientWrite has
increased so much and can we reduce it?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#115Robert Haas
robertmhaas@gmail.com
In reply to: Rushabh Lathia (#113)
Re: WIP/PoC for parallel backup

On Thu, May 21, 2020 at 2:06 AM Rushabh Lathia <rushabh.lathia@gmail.com> wrote:

Yes. My colleague Suraj tried this and here are the pg_stat_activity output files.

Captured wait events after every 3 seconds during the backup for -
1: parallel backup for 100GB data with 4 workers (pg_stat_activity_normal_backup_100GB.txt)
2: Normal backup (without parallel backup patch) for 100GB data (pg_stat_activity_j4_100GB.txt)

Here is the observation:

The total number of events (pg_stat_activity) captured during above runs:
- 314 events for normal backups
- 316 events for parallel backups (-j 4)

BaseBackupRead wait event numbers: (newly added)
37 - in normal backups
25 - in the parallel backup (-j 4)

ClientWrite wait event numbers:
175 - in normal backup
1098 - in parallel backups

ClientRead wait event numbers:
0 - ClientRead in normal backup
326 - ClientRead in parallel backups for diff processes. (all in idle state)

So, basically, when we go from 1 process to 4, the additional
processes spend all of their time waiting rather than doing any useful
work, and that's why there is no performance benefit. Presumably, the
reason they spend all their time waiting for ClientRead/ClientWrite is
because the network between the two machines is saturated, so adding
more processes that are trying to use it at maximum speed just leads
to spending more time waiting for it to be available.

Do we have the same results for the local backup case, where the patch helped?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#116Suraj Kharage
suraj.kharage@enterprisedb.com
In reply to: Robert Haas (#115)
2 attachment(s)
Re: WIP/PoC for parallel backup

On Thu, May 21, 2020 at 7:12 PM Robert Haas <robertmhaas@gmail.com> wrote:

So, basically, when we go from 1 process to 4, the additional
processes spend all of their time waiting rather than doing any useful
work, and that's why there is no performance benefit. Presumably, the
reason they spend all their time waiting for ClientRead/ClientWrite is
because the network between the two machines is saturated, so adding
more processes that are trying to use it at maximum speed just leads
to spending more time waiting for it to be available.

Do we have the same results for the local backup case, where the patch
helped?

Here is the result for local backup case (100GB data). Attaching the
captured logs.

The total number of events (pg_stat_activity) captured during local runs:
- 82 events for normal backups
- 31 events for parallel backups (-j 4)

BaseBackupRead wait event numbers: (newly added)
24 - in normal backups
14 - in parallel backup (-j 4)

ClientWrite wait event numbers:
8 - in normal backup
43 - in parallel backups

ClientRead wait event numbers:
0 - ClientRead in normal backup
32 - ClientRead in parallel backups for diff processes.

--
--

Thanks & Regards,
Suraj kharage,
EnterpriseDB Corporation,
The Postgres Database Company.

Attachments:

pg_stat_local_bk_j4.txttext/plain; charset=US-ASCII; name=pg_stat_local_bk_j4.txtDownload
pg_stat_local_normal_backup.txttext/plain; charset=US-ASCII; name=pg_stat_local_normal_backup.txtDownload
#117Hamid Akhtar
hamid.akhtar@gmail.com
In reply to: Suraj Kharage (#116)
Re: WIP/PoC for parallel backup

As far I understand, parallel backup is not a mandatory performance
feature, rather, one at user's discretion. This IMHO indicates that it will
benefit some users and it may not others.

Taking a backup is an I/O intensive workload. So by parallelizing it
through multiple worker threads/processes, creates an overhead of its own.
So what precisely are we optimizing here. Looking at a running database
system in any environment, I see the following potential scenarios playing
out. These are probably clear to everyone here, but I'm listing these for
completeness and clarity.

Locally Running Backup:
(1) Server has no clients connected other than base backup.
(2) Server has other clients connected which are actively performing
operations causing disk I/O.

Remotely Running Backup:
(3) Server has no clients connected other than remote base backup.
(4) Server has other clients connected which are actively performing
operations causing disk I/O.

Others:
(5) Server or the system running base backup has other processes competing
for disk or network bandwidth.

Generally speaking, I see that parallelization could potentially benefit in
scenarios (2), (4) and (5) with the reason being that having more than one
thread increases the likelihood that backup will now get a bigger time
slice for disk I/O and network bandwidth. With (1) and (3), since there are
no competing processes, addition of multiple threads or processes will only
increase CPU overhead whilst still getting the same network and disk time
slice. In this particular case, the performance will degrade.

IMHO, that’s why by adding other load on the server, perhaps by running
pgbench simultaneously may show improved performance for parallel backup.
Also, running parallel backup on a local laptop more often than yields
improved performance.

There are obviously other factors that may impact the performance like the
type of I/O scheduler being used whether CFQ or some other.

IMHO, parallel backup has obvious performance benefits, but we need to
ensure that users understand that there is potential for slower backup if
there is no competition for resources.

On Fri, May 22, 2020 at 11:03 AM Suraj Kharage <
suraj.kharage@enterprisedb.com> wrote:

On Thu, May 21, 2020 at 7:12 PM Robert Haas <robertmhaas@gmail.com> wrote:

So, basically, when we go from 1 process to 4, the additional
processes spend all of their time waiting rather than doing any useful
work, and that's why there is no performance benefit. Presumably, the
reason they spend all their time waiting for ClientRead/ClientWrite is
because the network between the two machines is saturated, so adding
more processes that are trying to use it at maximum speed just leads
to spending more time waiting for it to be available.

Do we have the same results for the local backup case, where the patch
helped?

Here is the result for local backup case (100GB data). Attaching the
captured logs.

The total number of events (pg_stat_activity) captured during local runs:
- 82 events for normal backups
- 31 events for parallel backups (-j 4)

BaseBackupRead wait event numbers: (newly added)
24 - in normal backups
14 - in parallel backup (-j 4)

ClientWrite wait event numbers:
8 - in normal backup
43 - in parallel backups

ClientRead wait event numbers:
0 - ClientRead in normal backup
32 - ClientRead in parallel backups for diff processes.

--
--

Thanks & Regards,
Suraj kharage,
EnterpriseDB Corporation,
The Postgres Database Company.

--
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
CELL:+923335449950 EMAIL: mailto:hamid.akhtar@highgo.ca
SKYPE: engineeredvirus

#118Robert Haas
robertmhaas@gmail.com
In reply to: Hamid Akhtar (#117)
Re: WIP/PoC for parallel backup

On Thu, Jun 11, 2020 at 1:41 PM Hamid Akhtar <hamid.akhtar@gmail.com> wrote:

As far I understand, parallel backup is not a mandatory performance feature, rather, one at user's discretion. This IMHO indicates that it will benefit some users and it may not others.

IMHO, parallel backup has obvious performance benefits, but we need to ensure that users understand that there is potential for slower backup if there is no competition for resources.

I am sure that nobody is arguing that the patch has to be beneficial
in all cases in order to justify applying it. However, there are
several good arguments against proceding with this patch:

* Every version of the patch that has been reviewed by anybody has
been riddled with errors. Over and over again, testers have found
serious bugs, and code reviewers have noticed lots of problems, too.

* This approach requires rewriting a lot of current functionality,
either by moving it to the client side or by restructuring it to work
with parallelism. That's a lot of work, and it seems likely to
generate more work in the future as people continue to add features.
It's one thing to add a feature that doesn't benefit everybody; it's
another thing to add a feature that doesn't benefit everybody and also
hinders future development. See
/messages/by-id/CA+TgmoZubLXYR+Pd_gi3MVgyv5hQdLm-GBrVXkun-Lewaw12Kg@mail.gmail.com
for more discussion of these issues.

* The scenarios in which the patch delivers a performance benefit are
narrow and somewhat contrived. In remote backup scenarios, AIUI, the
patch hasn't been shown to help. In local backups, it does, but how
likely is it that you are going to do your local backups over the wire
protocol instead of by direct file copy, which is probably much
faster? I agree that if your server is overloaded, having multiple
processes competing for the server resources will allow backup to get
a larger slice relative to other things, but that seems like a pretty
hackish and inefficient solution to that problem. You could also argue
that we could provide a feature to prioritize some queries over other
queries by running them with tons of parallel workers just to convince
the OS to give them more resources, and I guess that would work, but
it would also waste tons of resources and possibly cripple or even
crash your system if you used it enough. The same argument applies
here.

* Even when the patch does provide a benefit, it seems to max out at
about 2.5X. Clearly it's nice to have something go 2.5X faster, but
the point is that it doesn't scale beyond that no matter how many
workers you add. That doesn't automatically mean that something is a
bad idea, but it is a concern. At the very least, we should be able to
say why it doesn't scale any better than that.

* Actually, we have some hints about that. Over at
/messages/by-id/20200503174922.mfzzdafa5g4rlhez@alap3.anarazel.de
Andres has shown that too much concurrency when copying files results
in a dramatic performance reduction, and that a lot of the reason why
concurrency helps in the first place has to do with the fact that
pg_basebackup does not have any cache control (no fallocate,
sync_file_range(WRITE), posix_fadvise(DONTNEED)). When those things
are added the performance gets better and the benefits of concurrency
are reduced. I suspect that would also be true for this patch. It
would be unreasonable to commit a large patch, especially one that
would hinder future development, if we could get the same benefits
from a small patch that would not do so.

I am not in a position to tell you how to spend your time, so you can
certainly pursue this patch if you wish. However, I think it's
probably not the best use of time. Even if you fixed all the bugs and
reimplemented all of the functionality that needs reimplementing in
order to make this approach work, it still doesn't make sense to
commit the patch if either (a) we can obtain the same benefit, or most
of it, from a much simpler patch or (b) the patch is going to make it
significantly harder to develop other features that we want to have,
especially if those features seem likely to be more beneficial than
what this patch offers. I think both of those are likely true here.

For an example of (b), consider compression of tar files on the server
side before transmission to the client. If you take the approach this
patch does and move tarfile construction to the client, that is
impossible. Now you can argue (and perhaps you will) that this would
just mean someone has to choose between using this feature and using
that feature, and why should users not have such a choice? That is a
fair argument, but my counter-argument is that users shouldn't be
forced into making that choice. If the parallel feature is beneficial
enough to justify having it, then it ought to be designed in such a
way that it works with the other features we also want to have rather
than forcing users to choose between them. Since I have already
proposed (on the other thread linked above) a design that would make
that possible, and this design does not, I have a hard time
understanding why we would pick this one, especially given all of the
other disadvantages which it seems to have.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#119Daniel Gustafsson
daniel@yesql.se
In reply to: Robert Haas (#118)
Re: WIP/PoC for parallel backup

On 12 Jun 2020, at 19:28, Robert Haas <robertmhaas@gmail.com> wrote:

I am sure that nobody is arguing that the patch has to be beneficial
in all cases in order to justify applying it. However, there are
several good arguments against proceding with this patch:

This thread has stalled with no resolution to the raised issues, and the latest
version of the patch (v15) posted no longer applies (I only tried 0001 which
failed, the green tick in the CFBot is due it mistakenlt thinking an attached
report is a patch). I'm marking this patch Returned with Feedback. Please
open a new CF entry when there is a new version of the patch.

cheers ./daniel

#120Hamid Akhtar
hamid.akhtar@gmail.com
In reply to: Daniel Gustafsson (#119)
Re: WIP/PoC for parallel backup

On Mon, Jul 6, 2020 at 5:24 PM Daniel Gustafsson <daniel@yesql.se> wrote:

On 12 Jun 2020, at 19:28, Robert Haas <robertmhaas@gmail.com> wrote:

I am sure that nobody is arguing that the patch has to be beneficial
in all cases in order to justify applying it. However, there are
several good arguments against proceding with this patch:

This thread has stalled with no resolution to the raised issues, and the
latest
version of the patch (v15) posted no longer applies (I only tried 0001
which
failed, the green tick in the CFBot is due it mistakenlt thinking an
attached
report is a patch). I'm marking this patch Returned with Feedback. Please
open a new CF entry when there is a new version of the patch.

cheers ./daniel

I think this is fair. There are quite a few valid points raised by Robert.

--
Highgo Software (Canada/China/Pakistan)
URL : www.highgo.ca
ADDR: 10318 WHALLEY BLVD, Surrey, BC
CELL:+923335449950 EMAIL: mailto:hamid.akhtar@highgo.ca
SKYPE: engineeredvirus