summaryrefslogtreecommitdiff
path: root/0161-geo-rep-Fix-rename-with-existing-destination-with-sa.patch
diff options
context:
space:
mode:
Diffstat (limited to '0161-geo-rep-Fix-rename-with-existing-destination-with-sa.patch')
-rw-r--r--0161-geo-rep-Fix-rename-with-existing-destination-with-sa.patch289
1 files changed, 289 insertions, 0 deletions
diff --git a/0161-geo-rep-Fix-rename-with-existing-destination-with-sa.patch b/0161-geo-rep-Fix-rename-with-existing-destination-with-sa.patch
new file mode 100644
index 0000000..4522ec4
--- /dev/null
+++ b/0161-geo-rep-Fix-rename-with-existing-destination-with-sa.patch
@@ -0,0 +1,289 @@
+From 69ac1fd2da7a57f2f0854412863911959bf71fde Mon Sep 17 00:00:00 2001
+From: Sunny Kumar <sunkumar@redhat.com>
+Date: Tue, 2 Apr 2019 12:38:09 +0530
+Subject: [PATCH 161/169] geo-rep: Fix rename with existing destination with
+ same gfid
+
+Problem:
+ Geo-rep fails to sync the rename properly if destination exists.
+It results in source to be remained on slave causing more number of
+files on slave. Also heavy rename workload like logrotate caused
+lot of ESTALE errors
+
+Cause:
+ Geo-rep fails to sync rename if destination exists if creation
+of source file also falls into single batch of changelogs being
+processed. This is because, after fixing problematic gfids verifying
+from master, while re-processing original entries, CREATE also was
+re-processed causing more files on slave and rename to be failed.
+
+Solution:
+ Entries need to be removed from retrial list after fixing
+problematic gfids on slave so that it's not re-created again on slave.
+ Also treat ESTALE as EEXIST so that the error is properly handled
+verifying the op on master volume.
+
+Backport of:
+ > Patch: https://review.gluster.org/22519
+ > Change-Id: I50cf289e06b997adddff0552bf2466d9201dd1f9
+ > BUG: 1694820
+ > Signed-off-by: Kotresh HR <khiremat@redhat.com>
+ > Signed-off-by: Sunny Kumar <sunkumar@redhat.com>
+
+Change-Id: I50cf289e06b997adddff0552bf2466d9201dd1f9
+fixes: bz#1708121
+Signed-off-by: Kotresh HR <khiremat@redhat.com>
+Signed-off-by: Sunny Kumar <sunkumar@redhat.com>
+Reviewed-on: https://code.engineering.redhat.com/gerrit/172393
+Tested-by: RHGS Build Bot <nigelb@redhat.com>
+Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
+---
+ geo-replication/syncdaemon/master.py | 41 +++++++++++++++++++++--
+ geo-replication/syncdaemon/resource.py | 10 ++++--
+ tests/00-geo-rep/georep-basic-dr-rsync-arbiter.t | 5 +++
+ tests/00-geo-rep/georep-basic-dr-rsync.t | 5 +++
+ tests/00-geo-rep/georep-basic-dr-tarssh-arbiter.t | 5 +++
+ tests/00-geo-rep/georep-basic-dr-tarssh.t | 5 +++
+ tests/geo-rep.rc | 36 ++++++++++++++++++++
+ 7 files changed, 102 insertions(+), 5 deletions(-)
+
+diff --git a/geo-replication/syncdaemon/master.py b/geo-replication/syncdaemon/master.py
+index 3da7610..42c86d7 100644
+--- a/geo-replication/syncdaemon/master.py
++++ b/geo-replication/syncdaemon/master.py
+@@ -65,6 +65,9 @@ def _volinfo_hook_relax_foreign(self):
+ def edct(op, **ed):
+ dct = {}
+ dct['op'] = op
++ # This is used in automatic gfid conflict resolution.
++ # When marked True, it's skipped during re-processing.
++ dct['skip_entry'] = False
+ for k in ed:
+ if k == 'stat':
+ st = ed[k]
+@@ -792,6 +795,7 @@ class GMasterChangelogMixin(GMasterCommon):
+ pfx = gauxpfx()
+ fix_entry_ops = []
+ failures1 = []
++ remove_gfids = set()
+ for failure in failures:
+ if failure[2]['name_mismatch']:
+ pbname = failure[2]['slave_entry']
+@@ -822,6 +826,18 @@ class GMasterChangelogMixin(GMasterCommon):
+ edct('UNLINK',
+ gfid=failure[2]['slave_gfid'],
+ entry=pbname))
++ remove_gfids.add(slave_gfid)
++ if op in ['RENAME']:
++ # If renamed gfid doesn't exists on master, remove
++ # rename entry and unlink src on slave
++ st = lstat(os.path.join(pfx, failure[0]['gfid']))
++ if isinstance(st, int) and st == ENOENT:
++ logging.debug("Unlink source %s" % repr(failure))
++ remove_gfids.add(failure[0]['gfid'])
++ fix_entry_ops.append(
++ edct('UNLINK',
++ gfid=failure[0]['gfid'],
++ entry=failure[0]['entry']))
+ # Takes care of scenarios of hardlinks/renames on master
+ elif not isinstance(st, int):
+ if matching_disk_gfid(slave_gfid, pbname):
+@@ -831,7 +847,12 @@ class GMasterChangelogMixin(GMasterCommon):
+ ' Safe to ignore, take out entry',
+ retry_count=retry_count,
+ entry=repr(failure)))
+- entries.remove(failure[0])
++ remove_gfids.add(failure[0]['gfid'])
++ if op == 'RENAME':
++ fix_entry_ops.append(
++ edct('UNLINK',
++ gfid=failure[0]['gfid'],
++ entry=failure[0]['entry']))
+ # The file exists on master but with different name.
+ # Probably renamed and got missed during xsync crawl.
+ elif failure[2]['slave_isdir']:
+@@ -856,7 +877,10 @@ class GMasterChangelogMixin(GMasterCommon):
+ 'take out entry',
+ retry_count=retry_count,
+ entry=repr(failure)))
+- entries.remove(failure[0])
++ try:
++ entries.remove(failure[0])
++ except ValueError:
++ pass
+ else:
+ rename_dict = edct('RENAME', gfid=slave_gfid,
+ entry=src_entry,
+@@ -896,7 +920,10 @@ class GMasterChangelogMixin(GMasterCommon):
+ 'ignore, take out entry',
+ retry_count=retry_count,
+ entry=repr(failure)))
+- entries.remove(failure[0])
++ try:
++ entries.remove(failure[0])
++ except ValueError:
++ pass
+ else:
+ logging.info(lf('Fixing ENOENT error in slave. Create '
+ 'parent directory on slave.',
+@@ -913,6 +940,14 @@ class GMasterChangelogMixin(GMasterCommon):
+ edct('MKDIR', gfid=pargfid, entry=dir_entry,
+ mode=st.st_mode, uid=st.st_uid, gid=st.st_gid))
+
++ logging.debug("remove_gfids: %s" % repr(remove_gfids))
++ if remove_gfids:
++ for e in entries:
++ if e['op'] in ['MKDIR', 'MKNOD', 'CREATE', 'RENAME'] \
++ and e['gfid'] in remove_gfids:
++ logging.debug("Removed entry op from retrial list: entry: %s" % repr(e))
++ e['skip_entry'] = True
++
+ if fix_entry_ops:
+ # Process deletions of entries whose gfids are mismatched
+ failures1 = self.slave.server.entry_ops(fix_entry_ops)
+diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py
+index c290d86..f54ccd9 100644
+--- a/geo-replication/syncdaemon/resource.py
++++ b/geo-replication/syncdaemon/resource.py
+@@ -426,7 +426,7 @@ class Server(object):
+ e['stat']['uid'] = uid
+ e['stat']['gid'] = gid
+
+- if cmd_ret == EEXIST:
++ if cmd_ret in [EEXIST, ESTALE]:
+ if dst:
+ en = e['entry1']
+ else:
+@@ -510,6 +510,12 @@ class Server(object):
+ entry = e['entry']
+ uid = 0
+ gid = 0
++
++ # Skip entry processing if it's marked true during gfid
++ # conflict resolution
++ if e['skip_entry']:
++ continue
++
+ if e.get("stat", {}):
+ # Copy UID/GID value and then reset to zero. Copied UID/GID
+ # will be used to run chown once entry is created.
+@@ -688,7 +694,7 @@ class Server(object):
+ if blob:
+ cmd_ret = errno_wrap(Xattr.lsetxattr,
+ [pg, 'glusterfs.gfid.newfile', blob],
+- [EEXIST, ENOENT],
++ [EEXIST, ENOENT, ESTALE],
+ [ESTALE, EINVAL, EBUSY])
+ collect_failure(e, cmd_ret, uid, gid)
+
+diff --git a/tests/00-geo-rep/georep-basic-dr-rsync-arbiter.t b/tests/00-geo-rep/georep-basic-dr-rsync-arbiter.t
+index 67ac167..1a55ed2 100644
+--- a/tests/00-geo-rep/georep-basic-dr-rsync-arbiter.t
++++ b/tests/00-geo-rep/georep-basic-dr-rsync-arbiter.t
+@@ -203,6 +203,11 @@ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rsnapshot_data ${slave_mnt}
+ TEST gluster volume geo-rep $master $slave config rsync-options "--whole-file"
+ TEST "echo sampledata > $master_mnt/rsync_option_test_file"
+
++#rename with existing destination case BUG:1694820
++TEST create_rename_with_existing_destination ${master_mnt}
++#verify rename with existing destination case BUG:1694820
++EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rename_with_existing_destination ${slave_mnt}
++
+ #Verify arequal for whole volume
+ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 arequal_checksum ${master_mnt} ${slave_mnt}
+
+diff --git a/tests/00-geo-rep/georep-basic-dr-rsync.t b/tests/00-geo-rep/georep-basic-dr-rsync.t
+index 8b64370..d0c0fc9 100644
+--- a/tests/00-geo-rep/georep-basic-dr-rsync.t
++++ b/tests/00-geo-rep/georep-basic-dr-rsync.t
+@@ -204,6 +204,11 @@ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rsnapshot_data ${slave_mnt}
+ TEST gluster volume geo-rep $master $slave config rsync-options "--whole-file"
+ TEST "echo sampledata > $master_mnt/rsync_option_test_file"
+
++#rename with existing destination case BUG:1694820
++TEST create_rename_with_existing_destination ${master_mnt}
++#verify rename with existing destination case BUG:1694820
++EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rename_with_existing_destination ${slave_mnt}
++
+ #Verify arequal for whole volume
+ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 arequal_checksum ${master_mnt} ${slave_mnt}
+
+diff --git a/tests/00-geo-rep/georep-basic-dr-tarssh-arbiter.t b/tests/00-geo-rep/georep-basic-dr-tarssh-arbiter.t
+index 1726d0b..cb530ad 100644
+--- a/tests/00-geo-rep/georep-basic-dr-tarssh-arbiter.t
++++ b/tests/00-geo-rep/georep-basic-dr-tarssh-arbiter.t
+@@ -202,6 +202,11 @@ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_symlink_rename_mkdir_data ${slave_mnt}/s
+ #rsnapshot usecase
+ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rsnapshot_data ${slave_mnt}
+
++#rename with existing destination case BUG:1694820
++TEST create_rename_with_existing_destination ${master_mnt}
++#verify rename with existing destination case BUG:1694820
++EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rename_with_existing_destination ${slave_mnt}
++
+ #Verify arequal for whole volume
+ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 arequal_checksum ${master_mnt} ${slave_mnt}
+
+diff --git a/tests/00-geo-rep/georep-basic-dr-tarssh.t b/tests/00-geo-rep/georep-basic-dr-tarssh.t
+index c5d16ac..9e2f613 100644
+--- a/tests/00-geo-rep/georep-basic-dr-tarssh.t
++++ b/tests/00-geo-rep/georep-basic-dr-tarssh.t
+@@ -202,6 +202,11 @@ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_hardlink_rename_data ${slave_mnt}
+ #rsnapshot usecase
+ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rsnapshot_data ${slave_mnt}
+
++#rename with existing destination case BUG:1694820
++TEST create_rename_with_existing_destination ${master_mnt}
++#verify rename with existing destination case BUG:1694820
++EXPECT_WITHIN $GEO_REP_TIMEOUT 0 verify_rename_with_existing_destination ${slave_mnt}
++
+ #Verify arequal for whole volume
+ EXPECT_WITHIN $GEO_REP_TIMEOUT 0 arequal_checksum ${master_mnt} ${slave_mnt}
+
+diff --git a/tests/geo-rep.rc b/tests/geo-rep.rc
+index d723129..e357ba8 100644
+--- a/tests/geo-rep.rc
++++ b/tests/geo-rep.rc
+@@ -403,3 +403,39 @@ function check_slave_read_only()
+ gluster volume info $1 | grep 'features.read-only: on'
+ echo $?
+ }
++
++function create_rename_with_existing_destination()
++{
++ dir=$1/rename_with_existing_destination
++ mkdir $dir
++ for i in {1..5}
++ do
++ echo "Data_set$i" > $dir/data_set$i
++ mv $dir/data_set$i $dir/data_set -f
++ done
++}
++
++function verify_rename_with_existing_destination()
++{
++ dir=$1/rename_with_existing_destination
++
++ if [ ! -d $dir ]; then
++ echo 1
++ elif [ ! -f $dir/data_set ]; then
++ echo 2
++ elif [ -f $dir/data_set1 ]; then
++ echo 3
++ elif [ -f $dir/data_set2 ]; then
++ echo 4
++ elif [ -f $dir/data_set3 ]; then
++ echo 5
++ elif [ -f $dir/data_set4 ]; then
++ echo 6
++ elif [ -f $dir/data_set5 ]; then
++ echo 7
++ elif test "XData_set5" != "X$(cat $dir/data_set)"; then
++ echo 8
++ else
++ echo 0
++ fi
++}
+--
+1.8.3.1
+