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