a3470f
From 91cfe700849856245f58a8c0ee98c0fd1e9d47f6 Mon Sep 17 00:00:00 2001
a3470f
From: Kotresh HR <khiremat@redhat.com>
a3470f
Date: Mon, 28 May 2018 03:05:26 -0400
a3470f
Subject: [PATCH 304/305] cluster/dht: Fix rename journal in changelog
a3470f
a3470f
With patch [1], renames are journalled only
a3470f
on cached subvolume. The dht sends the special
a3470f
key on the cached subvolume so that the changelog
a3470f
journals the rename. With single distribute
a3470f
sub-volume, the key is not being set. This patch
a3470f
fixes the same.
a3470f
a3470f
[1] https://review.gluster.org/10410
a3470f
a3470f
Backport of:
a3470f
 > Patch: https://review.gluster.org/20093/
a3470f
 > fixes: bz#1583018
a3470f
 > Change-Id: Ic2e35b40535916fa506a714f257ba325e22d0961
a3470f
 > Signed-off-by: Kotresh HR <khiremat@redhat.com>
a3470f
a3470f
BUG: 1583047
a3470f
Change-Id: Ic2e35b40535916fa506a714f257ba325e22d0961
a3470f
Signed-off-by: Kotresh HR <khiremat@redhat.com>
a3470f
Reviewed-on: https://code.engineering.redhat.com/gerrit/142601
a3470f
Tested-by: RHGS Build Bot <nigelb@redhat.com>
a3470f
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
a3470f
---
a3470f
 tests/basic/changelog/changelog-rename.t |  44 ++++++
a3470f
 tests/utils/changelogparser.py           | 234 +++++++++++++++++++++++++++++++
a3470f
 tests/volume.rc                          |   7 +
a3470f
 xlators/cluster/dht/src/dht-rename.c     |  11 ++
a3470f
 4 files changed, 296 insertions(+)
a3470f
 create mode 100644 tests/basic/changelog/changelog-rename.t
a3470f
 create mode 100644 tests/utils/changelogparser.py
a3470f
a3470f
diff --git a/tests/basic/changelog/changelog-rename.t b/tests/basic/changelog/changelog-rename.t
a3470f
new file mode 100644
a3470f
index 0000000..9a0ef52
a3470f
--- /dev/null
a3470f
+++ b/tests/basic/changelog/changelog-rename.t
a3470f
@@ -0,0 +1,44 @@
a3470f
+#!/bin/bash
a3470f
+. $(dirname $0)/../../include.rc
a3470f
+. $(dirname $0)/../../volume.rc
a3470f
+cleanup;
a3470f
+
a3470f
+CHANGELOG_PATH_0="$B0/${V0}0/.glusterfs/changelogs"
a3470f
+ROLLOVER_TIME=30
a3470f
+
a3470f
+TEST glusterd
a3470f
+TEST pidof glusterd
a3470f
+TEST $CLI volume create $V0 $H0:$B0/${V0}0
a3470f
+TEST $CLI volume set $V0 changelog.changelog on
a3470f
+TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME
a3470f
+TEST $CLI volume start $V0
a3470f
+
a3470f
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0;
a3470f
+touch $M0/file1
a3470f
+mv $M0/file1 $M0/rn_file1
a3470f
+mkdir $M0/dir1
a3470f
+mv $M0/dir1 $M0/rn_dir1
a3470f
+
a3470f
+EXPECT "2" check_changelog_op ${CHANGELOG_PATH_0} "RENAME"
a3470f
+
a3470f
+cleanup;
a3470f
+
a3470f
+#####Test on multiple subvolume#####
a3470f
+#==========================================#
a3470f
+
a3470f
+TEST glusterd
a3470f
+TEST pidof glusterd
a3470f
+TEST $CLI volume create $V0 $H0:$B0/${V0}{0,1}
a3470f
+TEST $CLI volume set $V0 changelog.changelog on
a3470f
+TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME
a3470f
+TEST $CLI volume start $V0
a3470f
+
a3470f
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0;
a3470f
+touch $M0/gluster_file
a3470f
+mv $M0/gluster_file $M0/rn_gluster_file
a3470f
+mkdir $M0/dir1
a3470f
+mv $M0/dir1 $M0/rn_dir1
a3470f
+
a3470f
+EXPECT "2" check_changelog_op ${CHANGELOG_PATH_0} "RENAME"
a3470f
+
a3470f
+cleanup;
a3470f
diff --git a/tests/utils/changelogparser.py b/tests/utils/changelogparser.py
a3470f
new file mode 100644
a3470f
index 0000000..e173e52
a3470f
--- /dev/null
a3470f
+++ b/tests/utils/changelogparser.py
a3470f
@@ -0,0 +1,234 @@
a3470f
+#!/usr/bin/env python
a3470f
+# -*- coding: utf-8 -*-
a3470f
+"""
a3470f
+Why?
a3470f
+
a3470f
+Converts this
a3470f
+
a3470f
+GlusterFS Changelog | version: v1.1 | encoding : 2
a3470f
+E0b99ef11-4b79-4cd0-9730-b5a0e8c4a8c0^@4^@16877^@0^@0^@00000000-0000-0000-0000-
a3470f
+000000000001/dir1^@Ec5250af6-720e-4bfe-b938-827614304f39^@23^@33188^@0^@0^@0b99
a3470f
+ef11-4b79-4cd0-9730-b5a0e8c4a8c0/hello.txt^@Dc5250af6-720e-4bfe-b938-827614304f
a3470f
+39^@Dc5250af6-720e-4bfe-b938-827614304f39^@
a3470f
+
a3470f
+
a3470f
+to human readable :)
a3470f
+
a3470f
+E 0b99ef11-4b79-4cd0-9730-b5a0e8c4a8c0 MKDIR 16877 0 000000000-0000-0000-0000
a3470f
+  -000000000001/dir1
a3470f
+E c5250af6-720e-4bfe-b938-827614304f39 CREATE 33188 0 0 0b99ef11-4b79-4cd0-9730
a3470f
+  -b5a0e8c4a8c0/hello.txt
a3470f
+D c5250af6-720e-4bfe-b938-827614304f39
a3470f
+D c5250af6-720e-4bfe-b938-827614304f39
a3470f
+
a3470f
+
a3470f
+"""
a3470f
+import sys
a3470f
+import codecs
a3470f
+
a3470f
+ENTRY = 'E'
a3470f
+META = 'M'
a3470f
+DATA = 'D'
a3470f
+SEP = "\x00"
a3470f
+
a3470f
+GF_FOP = [
a3470f
+    "NULL", "STAT", "READLINK", "MKNOD", "MKDIR", "UNLINK",
a3470f
+    "RMDIR", "SYMLINK", "RENAME", "LINK", "TRUNCATE", "OPEN",
a3470f
+    "READ", "WRITE", "STATFS", "FLUSH", "FSYNC", "SETXATTR",
a3470f
+    "GETXATTR", "REMOVEXATTR", "OPENDIR", "FSYNCDIR", "ACCESS",
a3470f
+    "CREATE", "FTRUNCATE", "FSTAT", "LK", "LOOKUP", "READDIR",
a3470f
+    "INODELK", "FINODELK", "ENTRYLK", "FENTRYLK", "XATTROP",
a3470f
+    "FXATTROP", "FSETXATTR", "FGETXATTR", "RCHECKSUM", "SETATTR",
a3470f
+    "FSETATTR", "READDIRP", "GETSPEC", "FORGET", "RELEASE",
a3470f
+    "RELEASEDIR", "FREMOVEXATTR", "FALLOCATE", "DISCARD", "ZEROFILL"]
a3470f
+
a3470f
+
a3470f
+class NumTokens_V11(object):
a3470f
+    E = 7
a3470f
+    M = 3
a3470f
+    D = 2
a3470f
+    NULL = 3
a3470f
+    MKNOD = 7
a3470f
+    MKDIR = 7
a3470f
+    UNLINK = 4
a3470f
+    RMDIR = 4
a3470f
+    SYMLINK = 4
a3470f
+    RENAME = 5
a3470f
+    LINK = 4
a3470f
+    SETXATTR = 3
a3470f
+    REMOVEXATTR = 3
a3470f
+    CREATE = 7
a3470f
+    SETATTR = 3
a3470f
+    FTRUNCATE = 3
a3470f
+    FXATTROP = 3
a3470f
+
a3470f
+
a3470f
+class NumTokens_V12(NumTokens_V11):
a3470f
+    UNLINK = 5
a3470f
+    RMDIR = 5
a3470f
+
a3470f
+
a3470f
+class Version:
a3470f
+    V11 = "v1.1"
a3470f
+    V12 = "v1.2"
a3470f
+
a3470f
+
a3470f
+class Record(object):
a3470f
+    def __init__(self, **kwargs):
a3470f
+        self.ts = kwargs.get("ts", None)
a3470f
+        self.fop_type = kwargs.get("fop_type", None)
a3470f
+        self.gfid = kwargs.get("gfid", None)
a3470f
+        self.path = kwargs.get("path", None)
a3470f
+        self.fop = kwargs.get("fop", None)
a3470f
+        self.path1 = kwargs.get("path1", None)
a3470f
+        self.path2 = kwargs.get("path2", None)
a3470f
+        self.mode = kwargs.get("mode", None)
a3470f
+        self.uid = kwargs.get("uid", None)
a3470f
+        self.gid = kwargs.get("gid", None)
a3470f
+
a3470f
+    def create_mknod_mkdir(self, **kwargs):
a3470f
+        self.path = kwargs.get("path", None)
a3470f
+        self.fop = kwargs.get("fop", None)
a3470f
+        self.mode = kwargs.get("mode", None)
a3470f
+        self.uid = kwargs.get("uid", None)
a3470f
+        self.gid = kwargs.get("gid", None)
a3470f
+
a3470f
+    def metadata(self, **kwargs):
a3470f
+        self.fop = kwargs.get("fop", None)
a3470f
+
a3470f
+    def rename(self, **kwargs):
a3470f
+        self.fop = kwargs.get("fop", None)
a3470f
+        self.path1 = kwargs.get("path1", None)
a3470f
+        self.path2 = kwargs.get("path2", None)
a3470f
+
a3470f
+    def link_symlink_unlink_rmdir(self, **kwargs):
a3470f
+        self.path = kwargs.get("path", None)
a3470f
+        self.fop = kwargs.get("fop", None)
a3470f
+
a3470f
+    def __unicode__(self):
a3470f
+        if self.fop_type == "D":
a3470f
+            return u"{ts} {fop_type} {gfid}".format(**self.__dict__)
a3470f
+        elif self.fop_type == "M":
a3470f
+            return u"{ts} {fop_type} {gfid} {fop}".format(**self.__dict__)
a3470f
+        elif self.fop_type == "E":
a3470f
+            if self.fop in ["CREATE", "MKNOD", "MKDIR"]:
a3470f
+                return (u"{ts} {fop_type} {gfid} {fop} "
a3470f
+                        u"{path} {mode} {uid} {gid}".format(**self.__dict__))
a3470f
+            elif self.fop == "RENAME":
a3470f
+                return (u"{ts} {fop_type} {gfid} {fop} "
a3470f
+                        u"{path1} {path2}".format(**self.__dict__))
a3470f
+            elif self.fop in ["LINK", "SYMLINK", "UNLINK", "RMDIR"]:
a3470f
+                return (u"{ts} {fop_type} {gfid} {fop} "
a3470f
+                        u"{path}".format(**self.__dict__))
a3470f
+            else:
a3470f
+                return repr(self.__dict__)
a3470f
+        else:
a3470f
+            return repr(self.__dict__)
a3470f
+
a3470f
+    def __str__(self):
a3470f
+        return unicode(self).encode('utf-8')
a3470f
+
a3470f
+
a3470f
+def get_num_tokens(data, tokens, version=Version.V11):
a3470f
+    if version == Version.V11:
a3470f
+        cls_numtokens = NumTokens_V11
a3470f
+    elif version == Version.V12:
a3470f
+        cls_numtokens = NumTokens_V12
a3470f
+    else:
a3470f
+        sys.stderr.write("Unknown Changelog Version\n")
a3470f
+        sys.exit(1)
a3470f
+
a3470f
+    if data[tokens[0]] in [ENTRY, META]:
a3470f
+        if len(tokens) >= 3:
a3470f
+            return getattr(cls_numtokens, GF_FOP[int(data[tokens[2]])])
a3470f
+        else:
a3470f
+            return None
a3470f
+    else:
a3470f
+        return getattr(cls_numtokens, data[tokens[0]])
a3470f
+
a3470f
+
a3470f
+def process_record(data, tokens, changelog_ts, callback):
a3470f
+    if data[tokens[0]] in [ENTRY, META]:
a3470f
+        try:
a3470f
+            tokens[2] = GF_FOP[int(data[tokens[2]])]
a3470f
+        except ValueError:
a3470f
+            tokens[2] = "NULL"
a3470f
+
a3470f
+    if not changelog_ts:
a3470f
+        ts1 = int(changelog_ts)
a3470f
+    else:
a3470f
+        ts1=""
a3470f
+    record = Record(ts=ts1, fop_type=data[tokens[0]],
a3470f
+                    gfid=data[tokens[1]])
a3470f
+    if data[tokens[0]] == META:
a3470f
+        record.metadata(fop=tokens[2])
a3470f
+    elif data[tokens[0]] == ENTRY:
a3470f
+        if tokens[2] in ["CREATE", "MKNOD", "MKDIR"]:
a3470f
+            record.create_mknod_mkdir(fop=tokens[2],
a3470f
+                                      path=data[tokens[6]],
a3470f
+                                      mode=int(data[tokens[3]]),
a3470f
+                                      uid=int(data[tokens[4]]),
a3470f
+                                      gid=int(data[tokens[5]]))
a3470f
+        elif tokens[2] == "RENAME":
a3470f
+            record.rename(fop=tokens[2],
a3470f
+                          path1=data[tokens[3]],
a3470f
+                          path2=data[tokens[4]])
a3470f
+        if tokens[2] in ["LINK", "SYMLINK", "UNLINK", "RMDIR"]:
a3470f
+            record.link_symlink_unlink_rmdir(fop=tokens[2],
a3470f
+                                             path=data[tokens[3]])
a3470f
+    callback(record)
a3470f
+
a3470f
+
a3470f
+def default_callback(record):
a3470f
+    sys.stdout.write(u"{0}\n".format(record))
a3470f
+
a3470f
+
a3470f
+def parse(filename, callback=default_callback):
a3470f
+    data = None
a3470f
+    tokens = []
a3470f
+    changelog_ts = filename.rsplit(".")[-1]
a3470f
+    with codecs.open(filename, mode="rb", encoding="utf-8") as f:
a3470f
+        # GlusterFS Changelog | version: v1.1 | encoding : 2
a3470f
+        header = f.readline()
a3470f
+        version = header.split()[4]
a3470f
+
a3470f
+        data = f.readline()
a3470f
+
a3470f
+        slice_start = 0
a3470f
+        in_record = False
a3470f
+
a3470f
+        prev_char = ""
a3470f
+        next_char = ""
a3470f
+        for i, c in enumerate(data):
a3470f
+            next_char = ""
a3470f
+            if len(data) >= (i + 2):
a3470f
+                next_char = data[i+1]
a3470f
+
a3470f
+            if not in_record and c in [ENTRY, META, DATA]:
a3470f
+                tokens.append(slice(slice_start, i+1))
a3470f
+                slice_start = i+1
a3470f
+                in_record = True
a3470f
+                continue
a3470f
+
a3470f
+            if c == SEP and ((prev_char != SEP and next_char == SEP) or
a3470f
+                             (prev_char == SEP and next_char != SEP) or
a3470f
+                             (prev_char != SEP and next_char != SEP)):
a3470f
+                tokens.append(slice(slice_start, i))
a3470f
+                slice_start = i+1
a3470f
+
a3470f
+                num_tokens = get_num_tokens(data, tokens, version)
a3470f
+
a3470f
+                if num_tokens == len(tokens):
a3470f
+                    process_record(data, tokens, changelog_ts, callback)
a3470f
+                    in_record = False
a3470f
+                    tokens = []
a3470f
+
a3470f
+            prev_char = c
a3470f
+
a3470f
+        # process last record
a3470f
+        if slice_start < (len(data) - 1):
a3470f
+            tokens.append(slice(slice_start, len(data)))
a3470f
+            process_record(data, tokens, changelog_ts, callback)
a3470f
+            tokens = []
a3470f
+
a3470f
+parse(sys.argv[1])
a3470f
diff --git a/tests/volume.rc b/tests/volume.rc
a3470f
index f9e16c5..bba7e4e 100644
a3470f
--- a/tests/volume.rc
a3470f
+++ b/tests/volume.rc
a3470f
@@ -865,3 +865,10 @@ function get_mount_lru_size_value {
a3470f
         rm -f $statedump
a3470f
         echo $val
a3470f
 }
a3470f
+
a3470f
+function check_changelog_op {
a3470f
+        local clog_path=$1
a3470f
+        local op=$2
a3470f
+
a3470f
+        $PYTHON $(dirname $0)/../../utils/changelogparser.py ${clog_path}/CHANGELOG | grep $op | wc -l
a3470f
+}
a3470f
diff --git a/xlators/cluster/dht/src/dht-rename.c b/xlators/cluster/dht/src/dht-rename.c
a3470f
index d311ac6..1d0c2bb 100644
a3470f
--- a/xlators/cluster/dht/src/dht-rename.c
a3470f
+++ b/xlators/cluster/dht/src/dht-rename.c
a3470f
@@ -1948,6 +1948,7 @@ dht_rename (call_frame_t *frame, xlator_t *this,
a3470f
         dht_conf_t  *conf                   = NULL;
a3470f
         char         gfid[GF_UUID_BUF_SIZE] = {0};
a3470f
         char         newgfid[GF_UUID_BUF_SIZE] = {0};
a3470f
+        gf_boolean_t free_xdata             = _gf_false;
a3470f
 
a3470f
         VALIDATE_OR_GOTO (frame, err);
a3470f
         VALIDATE_OR_GOTO (this, err);
a3470f
@@ -1957,7 +1958,17 @@ dht_rename (call_frame_t *frame, xlator_t *this,
a3470f
         conf = this->private;
a3470f
 
a3470f
         if (conf->subvolume_cnt == 1) {
a3470f
+                if (!IA_ISDIR (oldloc->inode->ia_type)) {
a3470f
+                        if (!xdata) {
a3470f
+                                free_xdata = _gf_true;
a3470f
+                        }
a3470f
+                        DHT_CHANGELOG_TRACK_AS_RENAME(xdata, oldloc, newloc);
a3470f
+                }
a3470f
                 default_rename (frame, this, oldloc, newloc, xdata);
a3470f
+                if (free_xdata && xdata) {
a3470f
+                        dict_unref(xdata);
a3470f
+                        xdata = NULL;
a3470f
+                }
a3470f
                 return 0;
a3470f
         }
a3470f
 
a3470f
-- 
a3470f
1.8.3.1
a3470f