233933
From 29ec87484b1ee3ad6417c37726db8aa9296f3a83 Mon Sep 17 00:00:00 2001
233933
From: Kotresh HR <khiremat@redhat.com>
233933
Date: Wed, 8 May 2019 11:26:06 +0530
233933
Subject: [PATCH 163/169] geo-rep: Fix sync hang with tarssh
233933
233933
Problem:
233933
Geo-rep sync hangs when tarssh is used as sync
233933
engine at heavy workload.
233933
233933
Analysis and Root cause:
233933
It's found out that the tar process was hung.
233933
When debugged further, it's found out that stderr
233933
buffer of tar process on master was full i.e., 64k.
233933
When the buffer was copied to a file from /proc/pid/fd/2,
233933
the hang is resolved.
233933
233933
This can happen when files picked by tar process
233933
to sync doesn't exist on master anymore. If this count
233933
increases around 1k, the stderr buffer is filled up.
233933
233933
Fix:
233933
The tar process is executed using Popen with stderr as PIPE.
233933
The final execution is something like below.
233933
233933
tar | ssh <args> root@slave tar --overwrite -xf - -C <path>
233933
233933
It was waiting on ssh process first using communicate() and then tar.
233933
Note that communicate() reads stdout and stderr. So when stderr of tar
233933
process is filled up, there is no one to read until untar via ssh is
233933
completed. This can't happen and leads to deadlock.
233933
Hence we should be waiting on both process parallely, so that stderr is
233933
read on both processes.
233933
233933
Backport of:
233933
 > Patch: https://review.gluster.org/22684
233933
 > Change-Id: I609c7cc5c07e210c504771115b4d551a2e891adf
233933
 > BUG: 1707728
233933
 > Signed-off-by: Kotresh HR <khiremat@redhat.com>
233933
233933
Change-Id: I609c7cc5c07e210c504771115b4d551a2e891adf
233933
fixes: bz#1708116
233933
Signed-off-by: Kotresh HR <khiremat@redhat.com>
233933
Reviewed-on: https://code.engineering.redhat.com/gerrit/172395
233933
Tested-by: RHGS Build Bot <nigelb@redhat.com>
233933
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
233933
---
233933
 geo-replication/syncdaemon/resource.py |  22 ++++--
233933
 tests/00-geo-rep/georep-stderr-hang.t  | 128 +++++++++++++++++++++++++++++++++
233933
 tests/geo-rep.rc                       |  17 +++++
233933
 3 files changed, 163 insertions(+), 4 deletions(-)
233933
 create mode 100644 tests/00-geo-rep/georep-stderr-hang.t
233933
233933
diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py
233933
index 522279b..b16db60 100644
233933
--- a/geo-replication/syncdaemon/resource.py
233933
+++ b/geo-replication/syncdaemon/resource.py
233933
@@ -1540,15 +1540,29 @@ class SSH(object):
233933
 
233933
         p0.stdin.close()
233933
         p0.stdout.close()  # Allow p0 to receive a SIGPIPE if p1 exits.
233933
-        # wait for tar to terminate, collecting any errors, further
233933
-        # waiting for transfer to complete
233933
-        _, stderr1 = p1.communicate()
233933
 
233933
         # stdin and stdout of p0 is already closed, Reset to None and
233933
         # wait for child process to complete
233933
         p0.stdin = None
233933
         p0.stdout = None
233933
-        p0.communicate()
233933
+
233933
+        def wait_for_tar(p0):
233933
+            _, stderr = p0.communicate()
233933
+            if log_err:
233933
+                for errline in stderr.strip().split("\n")[:-1]:
233933
+                    if "No such file or directory" not in errline:
233933
+                        logging.error(lf("SYNC Error",
233933
+                                         sync_engine="Tarssh",
233933
+                                         error=errline))
233933
+
233933
+        t = syncdutils.Thread(target=wait_for_tar, args=(p0, ))
233933
+        # wait for tar to terminate, collecting any errors, further
233933
+        # waiting for transfer to complete
233933
+        t.start()
233933
+
233933
+        # wait for ssh process
233933
+        _, stderr1 = p1.communicate()
233933
+        t.join()
233933
 
233933
         if log_err:
233933
             for errline in stderr1.strip().split("\n")[:-1]:
233933
diff --git a/tests/00-geo-rep/georep-stderr-hang.t b/tests/00-geo-rep/georep-stderr-hang.t
233933
new file mode 100644
233933
index 0000000..496f0e6
233933
--- /dev/null
233933
+++ b/tests/00-geo-rep/georep-stderr-hang.t
233933
@@ -0,0 +1,128 @@
233933
+#!/bin/bash
233933
+
233933
+. $(dirname $0)/../include.rc
233933
+. $(dirname $0)/../volume.rc
233933
+. $(dirname $0)/../geo-rep.rc
233933
+. $(dirname $0)/../env.rc
233933
+
233933
+SCRIPT_TIMEOUT=500
233933
+
233933
+AREQUAL_PATH=$(dirname $0)/../utils
233933
+test "`uname -s`" != "Linux" && {
233933
+    CFLAGS="$CFLAGS -lintl";
233933
+}
233933
+build_tester $AREQUAL_PATH/arequal-checksum.c $CFLAGS
233933
+
233933
+### Basic Tests with Distribute Replicate volumes
233933
+
233933
+##Cleanup and start glusterd
233933
+cleanup;
233933
+TEST glusterd;
233933
+TEST pidof glusterd
233933
+
233933
+
233933
+##Variables
233933
+GEOREP_CLI="$CLI volume geo-replication"
233933
+master=$GMV0
233933
+SH0="127.0.0.1"
233933
+slave=${SH0}::${GSV0}
233933
+num_active=2
233933
+num_passive=2
233933
+master_mnt=$M0
233933
+slave_mnt=$M1
233933
+
233933
+############################################################
233933
+#SETUP VOLUMES AND GEO-REPLICATION
233933
+############################################################
233933
+
233933
+##create_and_start_master_volume
233933
+TEST $CLI volume create $GMV0 $H0:$B0/${GMV0}1;
233933
+TEST $CLI volume start $GMV0
233933
+
233933
+##create_and_start_slave_volume
233933
+TEST $CLI volume create $GSV0 $H0:$B0/${GSV0}1;
233933
+TEST $CLI volume start $GSV0
233933
+TEST $CLI volume set $GSV0 performance.stat-prefetch off
233933
+TEST $CLI volume set $GSV0 performance.quick-read off
233933
+TEST $CLI volume set $GSV0 performance.readdir-ahead off
233933
+TEST $CLI volume set $GSV0 performance.read-ahead off
233933
+
233933
+##Mount master
233933
+TEST glusterfs -s $H0 --volfile-id $GMV0 $M0
233933
+
233933
+##Mount slave
233933
+TEST glusterfs -s $H0 --volfile-id $GSV0 $M1
233933
+
233933
+############################################################
233933
+#BASIC GEO-REPLICATION TESTS
233933
+############################################################
233933
+
233933
+TEST create_georep_session $master $slave
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT 1 check_status_num_rows "Created"
233933
+
233933
+#Config gluster-command-dir
233933
+TEST $GEOREP_CLI $master $slave config gluster-command-dir ${GLUSTER_CMD_DIR}
233933
+
233933
+#Config gluster-command-dir
233933
+TEST $GEOREP_CLI $master $slave config slave-gluster-command-dir ${GLUSTER_CMD_DIR}
233933
+
233933
+#Set changelog roll-over time to 45 secs
233933
+TEST $CLI volume set $GMV0 changelog.rollover-time 45
233933
+
233933
+#Wait for common secret pem file to be created
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT  0 check_common_secret_file
233933
+
233933
+#Verify the keys are distributed
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT  0 check_keys_distributed
233933
+
233933
+#Set sync-jobs to 1
233933
+TEST $GEOREP_CLI $master $slave config sync-jobs 1
233933
+
233933
+#Start_georep
233933
+TEST $GEOREP_CLI $master $slave start
233933
+
233933
+touch $M0
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT  1 check_status_num_rows "Active"
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT  1 check_status_num_rows "Changelog Crawl"
233933
+
233933
+#Check History Crawl.
233933
+TEST $GEOREP_CLI $master $slave stop
233933
+TEST create_data_hang "rsync_hang"
233933
+TEST create_data "history_rsync"
233933
+TEST $GEOREP_CLI $master $slave start
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT  1 check_status_num_rows "Active"
233933
+
233933
+#Verify arequal for whole volume
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT "x0" arequal_checksum ${master_mnt} ${slave_mnt}
233933
+
233933
+#Stop Geo-rep
233933
+TEST $GEOREP_CLI $master $slave stop
233933
+
233933
+#Config tarssh as sync-engine
233933
+TEST $GEOREP_CLI $master $slave config sync-method tarssh
233933
+
233933
+#Create tarssh hang data
233933
+TEST create_data_hang "tarssh_hang"
233933
+TEST create_data "history_tar"
233933
+
233933
+TEST $GEOREP_CLI $master $slave start
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT  1 check_status_num_rows "Active"
233933
+
233933
+#Verify arequal for whole volume
233933
+EXPECT_WITHIN $GEO_REP_TIMEOUT "x0" arequal_checksum ${master_mnt} ${slave_mnt}
233933
+
233933
+#Stop Geo-rep
233933
+TEST $GEOREP_CLI $master $slave stop
233933
+
233933
+#Delete Geo-rep
233933
+TEST $GEOREP_CLI $master $slave delete
233933
+
233933
+#Cleanup are-equal binary
233933
+TEST rm $AREQUAL_PATH/arequal-checksum
233933
+
233933
+#Cleanup authorized keys
233933
+sed -i '/^command=.*SSH_ORIGINAL_COMMAND#.*/d' ~/.ssh/authorized_keys
233933
+sed -i '/^command=.*gsyncd.*/d' ~/.ssh/authorized_keys
233933
+
233933
+cleanup;
233933
+#G_TESTDEF_TEST_STATUS_NETBSD7=BAD_TEST,BUG=000000
233933
diff --git a/tests/geo-rep.rc b/tests/geo-rep.rc
233933
index 2035b9f..e4f014e 100644
233933
--- a/tests/geo-rep.rc
233933
+++ b/tests/geo-rep.rc
233933
@@ -101,6 +101,23 @@ function create_data()
233933
     chown 1000:1000 ${master_mnt}/${prefix}_chown_f1_ಸಂತಸ
233933
 }
233933
 
233933
+function create_data_hang()
233933
+{
233933
+    prefix=$1
233933
+    mkdir ${master_mnt}/${prefix}
233933
+    cd ${master_mnt}/${prefix}
233933
+    # ~1k files is required with 1 sync-job and hang happens if
233933
+    # stderr buffer of tar/ssh executed with Popen is full (i.e., 64k).
233933
+    # 64k is hit when ~800 files were  not found while syncing data
233933
+    # from master. So around 1k files is required to hit the condition.
233933
+    for i in {1..1000}
233933
+    do
233933
+        echo "test data" > file$i
233933
+        mv -f file$i file
233933
+    done
233933
+    cd -
233933
+}
233933
+
233933
 function chown_file_ok()
233933
 {
233933
     local file_owner=$(stat --format "%u:%g" "$1")
233933
-- 
233933
1.8.3.1
233933