|
|
d1681e |
From a9db68fc1f05639cb79defef6ed7da58572113ea Mon Sep 17 00:00:00 2001
|
|
|
d1681e |
From: Kotresh HR <khiremat@redhat.com>
|
|
|
d1681e |
Date: Thu, 5 Jul 2018 07:07:38 -0400
|
|
|
d1681e |
Subject: [PATCH 328/333] geo-rep: Fix issues with gfid conflict handling
|
|
|
d1681e |
|
|
|
d1681e |
1. MKDIR/RMDIR is recorded on all bricks. So if
|
|
|
d1681e |
one brick succeeds creating it, other bricks
|
|
|
d1681e |
should ignore it. But this was not happening.
|
|
|
d1681e |
The fix rename of directories in hybrid crawl,
|
|
|
d1681e |
was trying to rename the directory to itself
|
|
|
d1681e |
and in the process crashing with ENOENT if the
|
|
|
d1681e |
directory is removed.
|
|
|
d1681e |
|
|
|
d1681e |
2. If file is created, deleted and a directory is
|
|
|
d1681e |
created with same name, it was failing to sync.
|
|
|
d1681e |
Again the issue is around the fix for rename
|
|
|
d1681e |
of directories in hybrid crawl. Fixed the same.
|
|
|
d1681e |
|
|
|
d1681e |
If the same case was done with hardlink present
|
|
|
d1681e |
for the file, it was failing. This patch fixes
|
|
|
d1681e |
that too.
|
|
|
d1681e |
|
|
|
d1681e |
Backport of
|
|
|
d1681e |
> Patch: https://review.gluster.org/#/c/20473/
|
|
|
d1681e |
> fixes: bz#1598884
|
|
|
d1681e |
> Change-Id: I6f3bca44e194e415a3d4de3b9d03cc8976439284
|
|
|
d1681e |
> Signed-off-by: Kotresh HR <khiremat@redhat.com>
|
|
|
d1681e |
|
|
|
d1681e |
BUG: 1598384
|
|
|
d1681e |
Change-Id: I6f3bca44e194e415a3d4de3b9d03cc8976439284
|
|
|
d1681e |
Signed-off-by: Kotresh HR <khiremat@redhat.com>
|
|
|
d1681e |
Reviewed-on: https://code.engineering.redhat.com/gerrit/143400
|
|
|
d1681e |
Tested-by: RHGS Build Bot <nigelb@redhat.com>
|
|
|
d1681e |
Reviewed-by: Aravinda Vishwanathapura Krishna Murthy <avishwan@redhat.com>
|
|
|
d1681e |
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
|
|
|
d1681e |
---
|
|
|
d1681e |
geo-replication/syncdaemon/master.py | 157 ++++++++++++++++++++++---------
|
|
|
d1681e |
geo-replication/syncdaemon/resource.py | 57 ++++++-----
|
|
|
d1681e |
geo-replication/syncdaemon/syncdutils.py | 35 +++++++
|
|
|
d1681e |
3 files changed, 180 insertions(+), 69 deletions(-)
|
|
|
d1681e |
|
|
|
d1681e |
diff --git a/geo-replication/syncdaemon/master.py b/geo-replication/syncdaemon/master.py
|
|
|
d1681e |
index 64e9836..1399378 100644
|
|
|
d1681e |
--- a/geo-replication/syncdaemon/master.py
|
|
|
d1681e |
+++ b/geo-replication/syncdaemon/master.py
|
|
|
d1681e |
@@ -692,7 +692,8 @@ class GMasterChangelogMixin(GMasterCommon):
|
|
|
d1681e |
TYPE_GFID = "D "
|
|
|
d1681e |
TYPE_ENTRY = "E "
|
|
|
d1681e |
|
|
|
d1681e |
- MAX_EF_RETRIES = 15
|
|
|
d1681e |
+ MAX_EF_RETRIES = 10
|
|
|
d1681e |
+ MAX_OE_RETRIES = 5
|
|
|
d1681e |
|
|
|
d1681e |
# flat directory hierarchy for gfid based access
|
|
|
d1681e |
FLAT_DIR_HIERARCHY = '.'
|
|
|
d1681e |
@@ -788,38 +789,53 @@ class GMasterChangelogMixin(GMasterCommon):
|
|
|
d1681e |
|
|
|
d1681e |
self.status.inc_value("failures", num_failures)
|
|
|
d1681e |
|
|
|
d1681e |
- def fix_possible_entry_failures(self, failures, retry_count):
|
|
|
d1681e |
+ def fix_possible_entry_failures(self, failures, retry_count, entries):
|
|
|
d1681e |
pfx = gauxpfx()
|
|
|
d1681e |
fix_entry_ops = []
|
|
|
d1681e |
failures1 = []
|
|
|
d1681e |
for failure in failures:
|
|
|
d1681e |
- if failure[2]['dst']:
|
|
|
d1681e |
+ if failure[2]['name_mismatch']:
|
|
|
d1681e |
+ pbname = failure[2]['slave_entry']
|
|
|
d1681e |
+ elif failure[2]['dst']:
|
|
|
d1681e |
pbname = failure[0]['entry1']
|
|
|
d1681e |
else:
|
|
|
d1681e |
pbname = failure[0]['entry']
|
|
|
d1681e |
- if failure[2]['gfid_mismatch']:
|
|
|
d1681e |
+
|
|
|
d1681e |
+ op = failure[0]['op']
|
|
|
d1681e |
+ # name exists but gfid is different
|
|
|
d1681e |
+ if failure[2]['gfid_mismatch'] or failure[2]['name_mismatch']:
|
|
|
d1681e |
slave_gfid = failure[2]['slave_gfid']
|
|
|
d1681e |
st = lstat(os.path.join(pfx, slave_gfid))
|
|
|
d1681e |
+ # Takes care of scenarios with no hardlinks
|
|
|
d1681e |
if isinstance(st, int) and st == ENOENT:
|
|
|
d1681e |
- logging.info(lf('Fixing gfid mismatch in slave. Deleting'
|
|
|
d1681e |
- ' the entry', retry_count=retry_count,
|
|
|
d1681e |
+ logging.info(lf('Entry not present on master. Fixing gfid '
|
|
|
d1681e |
+ 'mismatch in slave. Deleting the entry',
|
|
|
d1681e |
+ retry_count=retry_count,
|
|
|
d1681e |
entry=repr(failure)))
|
|
|
d1681e |
- #Add deletion to fix_entry_ops list
|
|
|
d1681e |
+ # Add deletion to fix_entry_ops list
|
|
|
d1681e |
if failure[2]['slave_isdir']:
|
|
|
d1681e |
- fix_entry_ops.append(edct('RMDIR',
|
|
|
d1681e |
- gfid=failure[2]['slave_gfid'],
|
|
|
d1681e |
- entry=pbname))
|
|
|
d1681e |
+ fix_entry_ops.append(
|
|
|
d1681e |
+ edct('RMDIR',
|
|
|
d1681e |
+ gfid=failure[2]['slave_gfid'],
|
|
|
d1681e |
+ entry=pbname))
|
|
|
d1681e |
else:
|
|
|
d1681e |
- fix_entry_ops.append(edct('UNLINK',
|
|
|
d1681e |
- gfid=failure[2]['slave_gfid'],
|
|
|
d1681e |
- entry=pbname))
|
|
|
d1681e |
+ fix_entry_ops.append(
|
|
|
d1681e |
+ edct('UNLINK',
|
|
|
d1681e |
+ gfid=failure[2]['slave_gfid'],
|
|
|
d1681e |
+ entry=pbname))
|
|
|
d1681e |
+ # Takes care of scenarios of hardlinks/renames on master
|
|
|
d1681e |
elif not isinstance(st, int):
|
|
|
d1681e |
- #The file exists on master but with different name.
|
|
|
d1681e |
- #Probabaly renamed and got missed during xsync crawl.
|
|
|
d1681e |
- if failure[2]['slave_isdir']:
|
|
|
d1681e |
- logging.info(lf('Fixing gfid mismatch in slave',
|
|
|
d1681e |
+ if matching_disk_gfid(slave_gfid, pbname):
|
|
|
d1681e |
+ # Safe to ignore the failure as master contains same
|
|
|
d1681e |
+ # file with same gfid. Remove entry from entries list
|
|
|
d1681e |
+ logging.info(lf('Fixing gfid mismatch in slave. '
|
|
|
d1681e |
+ ' Safe to ignore, take out entry',
|
|
|
d1681e |
retry_count=retry_count,
|
|
|
d1681e |
entry=repr(failure)))
|
|
|
d1681e |
+ entries.remove(failure[0])
|
|
|
d1681e |
+ # The file exists on master but with different name.
|
|
|
d1681e |
+ # Probably renamed and got missed during xsync crawl.
|
|
|
d1681e |
+ elif failure[2]['slave_isdir']:
|
|
|
d1681e |
realpath = os.readlink(os.path.join(gconf.local_path,
|
|
|
d1681e |
".glusterfs",
|
|
|
d1681e |
slave_gfid[0:2],
|
|
|
d1681e |
@@ -827,64 +843,99 @@ class GMasterChangelogMixin(GMasterCommon):
|
|
|
d1681e |
slave_gfid))
|
|
|
d1681e |
dst_entry = os.path.join(pfx, realpath.split('/')[-2],
|
|
|
d1681e |
realpath.split('/')[-1])
|
|
|
d1681e |
- rename_dict = edct('RENAME', gfid=slave_gfid,
|
|
|
d1681e |
- entry=failure[0]['entry'],
|
|
|
d1681e |
- entry1=dst_entry, stat=st,
|
|
|
d1681e |
- link=None)
|
|
|
d1681e |
- logging.info(lf('Fixing gfid mismatch in slave. '
|
|
|
d1681e |
- 'Renaming', retry_count=retry_count,
|
|
|
d1681e |
- entry=repr(rename_dict)))
|
|
|
d1681e |
- fix_entry_ops.append(rename_dict)
|
|
|
d1681e |
+ src_entry = pbname
|
|
|
d1681e |
+ logging.info(lf('Fixing dir name/gfid mismatch in '
|
|
|
d1681e |
+ 'slave', retry_count=retry_count,
|
|
|
d1681e |
+ entry=repr(failure)))
|
|
|
d1681e |
+ if src_entry == dst_entry:
|
|
|
d1681e |
+ # Safe to ignore the failure as master contains
|
|
|
d1681e |
+ # same directory as in slave with same gfid.
|
|
|
d1681e |
+ # Remove the failure entry from entries list
|
|
|
d1681e |
+ logging.info(lf('Fixing dir name/gfid mismatch'
|
|
|
d1681e |
+ ' in slave. Safe to ignore, '
|
|
|
d1681e |
+ 'take out entry',
|
|
|
d1681e |
+ retry_count=retry_count,
|
|
|
d1681e |
+ entry=repr(failure)))
|
|
|
d1681e |
+ entries.remove(failure[0])
|
|
|
d1681e |
+ else:
|
|
|
d1681e |
+ rename_dict = edct('RENAME', gfid=slave_gfid,
|
|
|
d1681e |
+ entry=src_entry,
|
|
|
d1681e |
+ entry1=dst_entry, stat=st,
|
|
|
d1681e |
+ link=None)
|
|
|
d1681e |
+ logging.info(lf('Fixing dir name/gfid mismatch'
|
|
|
d1681e |
+ ' in slave. Renaming',
|
|
|
d1681e |
+ retry_count=retry_count,
|
|
|
d1681e |
+ entry=repr(rename_dict)))
|
|
|
d1681e |
+ fix_entry_ops.append(rename_dict)
|
|
|
d1681e |
else:
|
|
|
d1681e |
- logging.info(lf('Fixing gfid mismatch in slave. '
|
|
|
d1681e |
- ' Deleting the entry',
|
|
|
d1681e |
+ # A hardlink file exists with different name or
|
|
|
d1681e |
+ # renamed file exists and we are sure from
|
|
|
d1681e |
+ # matching_disk_gfid check that the entry doesn't
|
|
|
d1681e |
+ # exist with same gfid so we can safely delete on slave
|
|
|
d1681e |
+ logging.info(lf('Fixing file gfid mismatch in slave. '
|
|
|
d1681e |
+ 'Hardlink/Rename Case. Deleting entry',
|
|
|
d1681e |
+ retry_count=retry_count,
|
|
|
d1681e |
+ entry=repr(failure)))
|
|
|
d1681e |
+ fix_entry_ops.append(
|
|
|
d1681e |
+ edct('UNLINK',
|
|
|
d1681e |
+ gfid=failure[2]['slave_gfid'],
|
|
|
d1681e |
+ entry=pbname))
|
|
|
d1681e |
+ elif failure[1] == ENOENT:
|
|
|
d1681e |
+ # Ignore ENOENT error for fix_entry_ops aka retry_count > 1
|
|
|
d1681e |
+ if retry_count > 1:
|
|
|
d1681e |
+ logging.info(lf('ENOENT error while fixing entry ops. '
|
|
|
d1681e |
+ 'Safe to ignore, take out entry',
|
|
|
d1681e |
+ retry_count=retry_count,
|
|
|
d1681e |
+ entry=repr(failure)))
|
|
|
d1681e |
+ entries.remove(failure[0])
|
|
|
d1681e |
+ elif op in ('MKNOD', 'CREATE', 'MKDIR'):
|
|
|
d1681e |
+ pargfid = pbname.split('/')[1]
|
|
|
d1681e |
+ st = lstat(os.path.join(pfx, pargfid))
|
|
|
d1681e |
+ # Safe to ignore the failure as master doesn't contain
|
|
|
d1681e |
+ # parent directory.
|
|
|
d1681e |
+ if isinstance(st, int):
|
|
|
d1681e |
+ logging.info(lf('Fixing ENOENT error in slave. Parent '
|
|
|
d1681e |
+ 'does not exist on master. Safe to '
|
|
|
d1681e |
+ 'ignore, take out entry',
|
|
|
d1681e |
retry_count=retry_count,
|
|
|
d1681e |
entry=repr(failure)))
|
|
|
d1681e |
- fix_entry_ops.append(edct('UNLINK',
|
|
|
d1681e |
- gfid=failure[2]['slave_gfid'],
|
|
|
d1681e |
- entry=pbname))
|
|
|
d1681e |
- logging.error(lf('Entry cannot be fixed in slave due '
|
|
|
d1681e |
- 'to GFID mismatch, find respective '
|
|
|
d1681e |
- 'path for the GFID and trigger sync',
|
|
|
d1681e |
- gfid=slave_gfid))
|
|
|
d1681e |
+ entries.remove(failure[0])
|
|
|
d1681e |
|
|
|
d1681e |
if fix_entry_ops:
|
|
|
d1681e |
- #Process deletions of entries whose gfids are mismatched
|
|
|
d1681e |
+ # Process deletions of entries whose gfids are mismatched
|
|
|
d1681e |
failures1 = self.slave.server.entry_ops(fix_entry_ops)
|
|
|
d1681e |
- if not failures1:
|
|
|
d1681e |
- logging.info ("Sucessfully fixed entry ops with gfid mismatch")
|
|
|
d1681e |
|
|
|
d1681e |
- return failures1
|
|
|
d1681e |
+ return (failures1, fix_entry_ops)
|
|
|
d1681e |
|
|
|
d1681e |
def handle_entry_failures(self, failures, entries):
|
|
|
d1681e |
retries = 0
|
|
|
d1681e |
pending_failures = False
|
|
|
d1681e |
failures1 = []
|
|
|
d1681e |
failures2 = []
|
|
|
d1681e |
+ entry_ops1 = []
|
|
|
d1681e |
+ entry_ops2 = []
|
|
|
d1681e |
|
|
|
d1681e |
if failures:
|
|
|
d1681e |
pending_failures = True
|
|
|
d1681e |
failures1 = failures
|
|
|
d1681e |
+ entry_ops1 = entries
|
|
|
d1681e |
|
|
|
d1681e |
while pending_failures and retries < self.MAX_EF_RETRIES:
|
|
|
d1681e |
retries += 1
|
|
|
d1681e |
- failures2 = self.fix_possible_entry_failures(failures1,
|
|
|
d1681e |
- retries)
|
|
|
d1681e |
+ (failures2, entry_ops2) = self.fix_possible_entry_failures(
|
|
|
d1681e |
+ failures1, retries, entry_ops1)
|
|
|
d1681e |
if not failures2:
|
|
|
d1681e |
pending_failures = False
|
|
|
d1681e |
+ logging.info(lf('Sucessfully fixed entry ops with gfid '
|
|
|
d1681e |
+ 'mismatch', retry_count=retries))
|
|
|
d1681e |
else:
|
|
|
d1681e |
pending_failures = True
|
|
|
d1681e |
failures1 = failures2
|
|
|
d1681e |
+ entry_ops1 = entry_ops2
|
|
|
d1681e |
|
|
|
d1681e |
if pending_failures:
|
|
|
d1681e |
for failure in failures1:
|
|
|
d1681e |
logging.error("Failed to fix entry ops %s", repr(failure))
|
|
|
d1681e |
- else:
|
|
|
d1681e |
- #Retry original entry list 5 times
|
|
|
d1681e |
- failures = self.slave.server.entry_ops(entries)
|
|
|
d1681e |
-
|
|
|
d1681e |
- self.log_failures(failures, 'gfid', gauxpfx(), 'ENTRY')
|
|
|
d1681e |
-
|
|
|
d1681e |
|
|
|
d1681e |
def process_change(self, change, done, retry):
|
|
|
d1681e |
pfx = gauxpfx()
|
|
|
d1681e |
@@ -1112,7 +1163,19 @@ class GMasterChangelogMixin(GMasterCommon):
|
|
|
d1681e |
self.status.inc_value("entry", len(entries))
|
|
|
d1681e |
|
|
|
d1681e |
failures = self.slave.server.entry_ops(entries)
|
|
|
d1681e |
- self.handle_entry_failures(failures, entries)
|
|
|
d1681e |
+ count = 0
|
|
|
d1681e |
+ while failures and count < self.MAX_OE_RETRIES:
|
|
|
d1681e |
+ count += 1
|
|
|
d1681e |
+ self.handle_entry_failures(failures, entries)
|
|
|
d1681e |
+ logging.info("Retry original entries. count = %s" % count)
|
|
|
d1681e |
+ failures = self.slave.server.entry_ops(entries)
|
|
|
d1681e |
+ if not failures:
|
|
|
d1681e |
+ logging.info("Sucessfully fixed all entry ops with gfid "
|
|
|
d1681e |
+ "mismatch")
|
|
|
d1681e |
+ break
|
|
|
d1681e |
+
|
|
|
d1681e |
+ self.log_failures(failures, 'gfid', gauxpfx(), 'ENTRY')
|
|
|
d1681e |
+
|
|
|
d1681e |
self.status.dec_value("entry", len(entries))
|
|
|
d1681e |
|
|
|
d1681e |
# Update Entry stime in Brick Root only in case of Changelog mode
|
|
|
d1681e |
diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py
|
|
|
d1681e |
index 0d5462a..eb696f3 100644
|
|
|
d1681e |
--- a/geo-replication/syncdaemon/resource.py
|
|
|
d1681e |
+++ b/geo-replication/syncdaemon/resource.py
|
|
|
d1681e |
@@ -38,9 +38,9 @@ from syncdutils import CHANGELOG_AGENT_CLIENT_VERSION
|
|
|
d1681e |
from syncdutils import GX_GFID_CANONICAL_LEN
|
|
|
d1681e |
from gsyncdstatus import GeorepStatus
|
|
|
d1681e |
from syncdutils import get_master_and_slave_data_from_args
|
|
|
d1681e |
-from syncdutils import lf, Popen, sup, Volinfo
|
|
|
d1681e |
+from syncdutils import lf, Popen, sup
|
|
|
d1681e |
from syncdutils import Xattr, matching_disk_gfid, get_gfid_from_mnt
|
|
|
d1681e |
-from syncdutils import unshare_propagation_supported
|
|
|
d1681e |
+from syncdutils import unshare_propagation_supported, get_slv_dir_path
|
|
|
d1681e |
|
|
|
d1681e |
UrlRX = re.compile('\A(\w+)://([^ *?[]*)\Z')
|
|
|
d1681e |
HostRX = re.compile('[a-zA-Z\d](?:[a-zA-Z\d.-]*[a-zA-Z\d])?', re.I)
|
|
|
d1681e |
@@ -50,7 +50,6 @@ ENOTSUP = getattr(errno, 'ENOTSUP', 'EOPNOTSUPP')
|
|
|
d1681e |
|
|
|
d1681e |
slv_volume = None
|
|
|
d1681e |
slv_host = None
|
|
|
d1681e |
-slv_bricks = None
|
|
|
d1681e |
|
|
|
d1681e |
def desugar(ustr):
|
|
|
d1681e |
"""transform sugared url strings to standard <scheme>://<urlbody> form
|
|
|
d1681e |
@@ -463,13 +462,23 @@ class Server(object):
|
|
|
d1681e |
# to be purged is the GFID gotten from the changelog.
|
|
|
d1681e |
# (a stat(changelog_gfid) would also be valid here)
|
|
|
d1681e |
# The race here is between the GFID check and the purge.
|
|
|
d1681e |
+
|
|
|
d1681e |
+ # If the entry or the gfid of the file to be deleted is not present
|
|
|
d1681e |
+ # on slave, we can ignore the unlink/rmdir
|
|
|
d1681e |
+ if isinstance(lstat(entry), int) or \
|
|
|
d1681e |
+ isinstance(lstat(os.path.join(pfx, gfid)), int):
|
|
|
d1681e |
+ return
|
|
|
d1681e |
+
|
|
|
d1681e |
if not matching_disk_gfid(gfid, entry):
|
|
|
d1681e |
collect_failure(e, EEXIST)
|
|
|
d1681e |
return
|
|
|
d1681e |
|
|
|
d1681e |
if op == 'UNLINK':
|
|
|
d1681e |
er = errno_wrap(os.unlink, [entry], [ENOENT, ESTALE], [EBUSY])
|
|
|
d1681e |
- return er
|
|
|
d1681e |
+ # EISDIR is safe error, ignore. This can only happen when
|
|
|
d1681e |
+ # unlink is sent from master while fixing gfid conflicts.
|
|
|
d1681e |
+ if er != EISDIR:
|
|
|
d1681e |
+ return er
|
|
|
d1681e |
|
|
|
d1681e |
elif op == 'RMDIR':
|
|
|
d1681e |
er = errno_wrap(os.rmdir, [entry], [ENOENT, ESTALE,
|
|
|
d1681e |
@@ -480,7 +489,11 @@ class Server(object):
|
|
|
d1681e |
def collect_failure(e, cmd_ret, dst=False):
|
|
|
d1681e |
slv_entry_info = {}
|
|
|
d1681e |
slv_entry_info['gfid_mismatch'] = False
|
|
|
d1681e |
+ slv_entry_info['name_mismatch'] = False
|
|
|
d1681e |
slv_entry_info['dst'] = dst
|
|
|
d1681e |
+ slv_entry_info['slave_isdir'] = False
|
|
|
d1681e |
+ slv_entry_info['slave_name'] = None
|
|
|
d1681e |
+ slv_entry_info['slave_gfid'] = None
|
|
|
d1681e |
# We do this for failing fops on Slave
|
|
|
d1681e |
# Master should be logging this
|
|
|
d1681e |
if cmd_ret is None:
|
|
|
d1681e |
@@ -498,6 +511,9 @@ class Server(object):
|
|
|
d1681e |
if not isinstance(st, int):
|
|
|
d1681e |
if st and stat.S_ISDIR(st.st_mode):
|
|
|
d1681e |
slv_entry_info['slave_isdir'] = True
|
|
|
d1681e |
+ dir_name = get_slv_dir_path(slv_host, slv_volume,
|
|
|
d1681e |
+ disk_gfid)
|
|
|
d1681e |
+ slv_entry_info['slave_name'] = dir_name
|
|
|
d1681e |
else:
|
|
|
d1681e |
slv_entry_info['slave_isdir'] = False
|
|
|
d1681e |
slv_entry_info['slave_gfid'] = disk_gfid
|
|
|
d1681e |
@@ -618,37 +634,34 @@ class Server(object):
|
|
|
d1681e |
[ENOENT, EEXIST], [ESTALE])
|
|
|
d1681e |
collect_failure(e, cmd_ret)
|
|
|
d1681e |
elif op == 'MKDIR':
|
|
|
d1681e |
+ en = e['entry']
|
|
|
d1681e |
slink = os.path.join(pfx, gfid)
|
|
|
d1681e |
st = lstat(slink)
|
|
|
d1681e |
# don't create multiple entries with same gfid
|
|
|
d1681e |
if isinstance(st, int):
|
|
|
d1681e |
blob = entry_pack_mkdir(
|
|
|
d1681e |
gfid, bname, e['mode'], e['uid'], e['gid'])
|
|
|
d1681e |
- else:
|
|
|
d1681e |
+ elif (isinstance(lstat(en), int) or
|
|
|
d1681e |
+ not matching_disk_gfid(gfid, en)):
|
|
|
d1681e |
# If gfid of a directory exists on slave but path based
|
|
|
d1681e |
# create is getting EEXIST. This means the directory is
|
|
|
d1681e |
# renamed in master but recorded as MKDIR during hybrid
|
|
|
d1681e |
# crawl. Get the directory path by reading the backend
|
|
|
d1681e |
# symlink and trying to rename to new name as said by
|
|
|
d1681e |
# master.
|
|
|
d1681e |
- global slv_bricks
|
|
|
d1681e |
- global slv_volume
|
|
|
d1681e |
- global slv_host
|
|
|
d1681e |
- if not slv_bricks:
|
|
|
d1681e |
- slv_info = Volinfo (slv_volume, slv_host)
|
|
|
d1681e |
- slv_bricks = slv_info.bricks
|
|
|
d1681e |
- # Result of readlink would be of format as below.
|
|
|
d1681e |
- # readlink = "../../pgfid[0:2]/pgfid[2:4]/pgfid/basename"
|
|
|
d1681e |
- realpath = os.readlink(os.path.join(slv_bricks[0]['dir'],
|
|
|
d1681e |
- ".glusterfs", gfid[0:2],
|
|
|
d1681e |
- gfid[2:4], gfid))
|
|
|
d1681e |
- realpath_parts = realpath.split('/')
|
|
|
d1681e |
- src_pargfid = realpath_parts[-2]
|
|
|
d1681e |
- src_basename = realpath_parts[-1]
|
|
|
d1681e |
- src_entry = os.path.join(pfx, src_pargfid, src_basename)
|
|
|
d1681e |
logging.info(lf("Special case: rename on mkdir",
|
|
|
d1681e |
- gfid=gfid, entry=repr(entry)))
|
|
|
d1681e |
- rename_with_disk_gfid_confirmation(gfid, src_entry, entry)
|
|
|
d1681e |
+ gfid=gfid, entry=repr(entry)))
|
|
|
d1681e |
+ src_entry = get_slv_dir_path(slv_host, slv_volume, gfid)
|
|
|
d1681e |
+ if src_entry is not None and src_entry != entry:
|
|
|
d1681e |
+ slv_entry_info = {}
|
|
|
d1681e |
+ slv_entry_info['gfid_mismatch'] = False
|
|
|
d1681e |
+ slv_entry_info['name_mismatch'] = True
|
|
|
d1681e |
+ slv_entry_info['dst'] = False
|
|
|
d1681e |
+ slv_entry_info['slave_isdir'] = True
|
|
|
d1681e |
+ slv_entry_info['slave_gfid'] = gfid
|
|
|
d1681e |
+ slv_entry_info['slave_entry'] = src_entry
|
|
|
d1681e |
+
|
|
|
d1681e |
+ failures.append((e, EEXIST, slv_entry_info))
|
|
|
d1681e |
elif op == 'LINK':
|
|
|
d1681e |
slink = os.path.join(pfx, gfid)
|
|
|
d1681e |
st = lstat(slink)
|
|
|
d1681e |
diff --git a/geo-replication/syncdaemon/syncdutils.py b/geo-replication/syncdaemon/syncdutils.py
|
|
|
d1681e |
index 6dafb0a..d798356 100644
|
|
|
d1681e |
--- a/geo-replication/syncdaemon/syncdutils.py
|
|
|
d1681e |
+++ b/geo-replication/syncdaemon/syncdutils.py
|
|
|
d1681e |
@@ -77,6 +77,7 @@ CHANGELOG_AGENT_CLIENT_VERSION = 1.0
|
|
|
d1681e |
NodeID = None
|
|
|
d1681e |
rsync_version = None
|
|
|
d1681e |
unshare_mnt_propagation = None
|
|
|
d1681e |
+slv_bricks = None
|
|
|
d1681e |
SPACE_ESCAPE_CHAR = "%20"
|
|
|
d1681e |
NEWLINE_ESCAPE_CHAR = "%0A"
|
|
|
d1681e |
PERCENTAGE_ESCAPE_CHAR = "%25"
|
|
|
d1681e |
@@ -671,6 +672,40 @@ def get_rsync_version(rsync_cmd):
|
|
|
d1681e |
return rsync_version
|
|
|
d1681e |
|
|
|
d1681e |
|
|
|
d1681e |
+def get_slv_dir_path(slv_host, slv_volume, gfid):
|
|
|
d1681e |
+ global slv_bricks
|
|
|
d1681e |
+
|
|
|
d1681e |
+ dir_path = ENOENT
|
|
|
d1681e |
+
|
|
|
d1681e |
+ if not slv_bricks:
|
|
|
d1681e |
+ slv_info = Volinfo(slv_volume, slv_host)
|
|
|
d1681e |
+ slv_bricks = slv_info.bricks
|
|
|
d1681e |
+ # Result of readlink would be of format as below.
|
|
|
d1681e |
+ # readlink = "../../pgfid[0:2]/pgfid[2:4]/pgfid/basename"
|
|
|
d1681e |
+ for brick in slv_bricks:
|
|
|
d1681e |
+ dir_path = errno_wrap(os.path.join,
|
|
|
d1681e |
+ [brick['dir'],
|
|
|
d1681e |
+ ".glusterfs", gfid[0:2],
|
|
|
d1681e |
+ gfid[2:4],
|
|
|
d1681e |
+ gfid], [ENOENT], [ESTALE])
|
|
|
d1681e |
+ if dir_path != ENOENT:
|
|
|
d1681e |
+ break
|
|
|
d1681e |
+
|
|
|
d1681e |
+ if not isinstance(dir_path, int):
|
|
|
d1681e |
+ realpath = errno_wrap(os.readlink, [dir_path],
|
|
|
d1681e |
+ [ENOENT], [ESTALE])
|
|
|
d1681e |
+
|
|
|
d1681e |
+ if not isinstance(realpath, int):
|
|
|
d1681e |
+ realpath_parts = realpath.split('/')
|
|
|
d1681e |
+ pargfid = realpath_parts[-2]
|
|
|
d1681e |
+ basename = realpath_parts[-1]
|
|
|
d1681e |
+ pfx = gauxpfx()
|
|
|
d1681e |
+ dir_entry = os.path.join(pfx, pargfid, basename)
|
|
|
d1681e |
+ return dir_entry
|
|
|
d1681e |
+
|
|
|
d1681e |
+ return None
|
|
|
d1681e |
+
|
|
|
d1681e |
+
|
|
|
d1681e |
def lf(event, **kwargs):
|
|
|
d1681e |
"""
|
|
|
d1681e |
Log Format helper function, log messages can be
|
|
|
d1681e |
--
|
|
|
d1681e |
1.8.3.1
|
|
|
d1681e |
|