887953
From f005377a54f01edc046aa668c8ab924a3ddf52bb Mon Sep 17 00:00:00 2001
887953
From: Kotresh HR <khiremat@redhat.com>
887953
Date: Tue, 21 Aug 2018 06:09:44 -0400
887953
Subject: [PATCH 370/385] libgfchangelog: Fix changelog history API
887953
887953
Problem:
887953
If requested start time and end time doesn't fall into
887953
first HTIME file, then history API fails even though
887953
continuous changelogs are avaiable for the requested range
887953
in other HTIME files. This is induced by changelog disable
887953
and enable which creates fresh HTIME index file.
887953
887953
Cause and Analysis:
887953
Each HTIME index file represents the availability of
887953
continuous changelogs. If changelog is disabled and enabled,
887953
a new HTIME index file is created represents non availability
887953
of continuous changelogs. So as long as the requested start
887953
and end falls into single HTIME index file and not across,
887953
history API should succeed.
887953
887953
But History API checks for the changelogs only in first
887953
HTIME index file and errors out if not available.
887953
887953
Fix:
887953
Check in all HTIME index files for availability of continuous
887953
changelogs for requested change.
887953
887953
Upstream Patch : https://review.gluster.org/#/c/glusterfs/+/21016/
887953
887953
>fixes: bz#1622549
887953
>Signed-off-by: Kotresh HR <khiremat@redhat.com>
887953
887953
Change-Id: I80eeceb5afbd1b89f86a9dc4c320e161907d3559
887953
BUG: 1627639
887953
Signed-off-by: Sunny Kumar <sunkumar@redhat.com>
887953
Reviewed-on: https://code.engineering.redhat.com/gerrit/149768
887953
Tested-by: RHGS Build Bot <nigelb@redhat.com>
887953
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
887953
---
887953
 tests/basic/changelog/changelog-history.t          |  86 +++++++++++++++
887953
 tests/utils/changelog/changelog.h                  | 120 +++++++++++++++++++++
887953
 tests/utils/changelog/get-history.c                |  73 +++++++++++++
887953
 .../changelog/lib/src/gf-history-changelog.c       |  59 ++++++++--
887953
 4 files changed, 331 insertions(+), 7 deletions(-)
887953
 create mode 100644 tests/basic/changelog/changelog-history.t
887953
 create mode 100644 tests/utils/changelog/changelog.h
887953
 create mode 100644 tests/utils/changelog/get-history.c
887953
887953
diff --git a/tests/basic/changelog/changelog-history.t b/tests/basic/changelog/changelog-history.t
887953
new file mode 100644
887953
index 0000000..3ce4098
887953
--- /dev/null
887953
+++ b/tests/basic/changelog/changelog-history.t
887953
@@ -0,0 +1,86 @@
887953
+#!/bin/bash
887953
+. $(dirname $0)/../../include.rc
887953
+. $(dirname $0)/../../volume.rc
887953
+. $(dirname $0)/../../env.rc
887953
+
887953
+cleanup;
887953
+
887953
+HISTORY_BIN_PATH=$(dirname $0)/../../utils/changelog
887953
+build_tester $HISTORY_BIN_PATH/get-history.c -lgfchangelog
887953
+
887953
+time_before_enable1=$(date '+%s')
887953
+CHANGELOG_PATH_0="$B0/${V0}0/.glusterfs/changelogs"
887953
+ROLLOVER_TIME=2
887953
+
887953
+TEST glusterd
887953
+TEST pidof glusterd
887953
+
887953
+sleep 3
887953
+time_before_enable2=$(date '+%s')
887953
+
887953
+sleep 3
887953
+TEST $CLI volume create $V0 $H0:$B0/${V0}0
887953
+TEST $CLI volume set $V0 changelog.changelog on
887953
+TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME
887953
+TEST $CLI volume start $V0
887953
+
887953
+sleep 3
887953
+time_after_enable1=$(date '+%s')
887953
+
887953
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0;
887953
+touch $M0/file{1..10}
887953
+
887953
+sleep 3
887953
+time_after_enable2=$(date '+%s')
887953
+
887953
+let time_future=time_after_enable2+600
887953
+
887953
+#Fails as start falls before changelog enable
887953
+EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_before_enable1 $time_before_enable2
887953
+
887953
+#Fails as start falls before changelog enable
887953
+EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_before_enable2 $time_after_enable1
887953
+
887953
+#Passes as start and end falls in same htime file
887953
+EXPECT "0" $HISTORY_BIN_PATH/get-history $time_after_enable1 $time_after_enable2
887953
+
887953
+#Passes, gives the changelogs till continuous changelogs are available
887953
+# but returns 1
887953
+EXPECT "1" $HISTORY_BIN_PATH/get-history $time_after_enable2 $time_future
887953
+
887953
+#Disable and enable changelog
887953
+TEST $CLI volume set $V0 changelog.changelog off
887953
+sleep 6
887953
+time_between_htime=$(date '+%s')
887953
+sleep 6
887953
+TEST $CLI volume set $V0 changelog.changelog on
887953
+
887953
+sleep 6
887953
+touch $M0/test{1..10}
887953
+time_in_sec_htime1=$(date '+%s')
887953
+
887953
+sleep 6
887953
+touch $M0/test1{1..10}
887953
+time_in_sec_htime2=$(date '+%s')
887953
+
887953
+sleep 3
887953
+TEST $CLI volume set $V0 changelog.changelog off
887953
+sleep 3
887953
+time_after_disable=$(date '+%s')
887953
+
887953
+#Passes, gives the changelogs till continuous changelogs are available
887953
+# but returns 1
887953
+EXPECT "1" $HISTORY_BIN_PATH/get-history $time_after_enable1 $time_in_sec_htime2
887953
+
887953
+#Fails as start falls between htime files
887953
+EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_between_htime $time_in_sec_htime1
887953
+
887953
+#Passes as start and end falls in same htime file
887953
+EXPECT "0" $HISTORY_BIN_PATH/get-history $time_in_sec_htime1 $time_in_sec_htime2
887953
+
887953
+#Passes, gives the changelogs till continuous changelogs are available
887953
+EXPECT "0" $HISTORY_BIN_PATH/get-history $time_in_sec_htime2 $time_after_disable
887953
+
887953
+TEST rm $HISTORY_BIN_PATH/get-history
887953
+
887953
+cleanup;
887953
diff --git a/tests/utils/changelog/changelog.h b/tests/utils/changelog/changelog.h
887953
new file mode 100644
887953
index 0000000..14094cf
887953
--- /dev/null
887953
+++ b/tests/utils/changelog/changelog.h
887953
@@ -0,0 +1,120 @@
887953
+/*
887953
+   Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
887953
+   This file is part of GlusterFS.
887953
+
887953
+   This file is licensed to you under your choice of the GNU Lesser
887953
+   General Public License, version 3 or any later version (LGPLv3 or
887953
+   later), or the GNU General Public License, version 2 (GPLv2), in all
887953
+   cases as published by the Free Software Foundation.
887953
+*/
887953
+
887953
+#ifndef _GF_CHANGELOG_H
887953
+#define _GF_CHANGELOG_H
887953
+
887953
+struct gf_brick_spec;
887953
+
887953
+/**
887953
+ * Max bit shiter for event selection
887953
+ */
887953
+#define CHANGELOG_EV_SELECTION_RANGE  5
887953
+
887953
+#define CHANGELOG_OP_TYPE_JOURNAL    (1<<0)
887953
+#define CHANGELOG_OP_TYPE_OPEN       (1<<1)
887953
+#define CHANGELOG_OP_TYPE_CREATE     (1<<2)
887953
+#define CHANGELOG_OP_TYPE_RELEASE    (1<<3)
887953
+#define CHANGELOG_OP_TYPE_BR_RELEASE (1<<4)  /* logical release (last close()),
887953
+                                                sent by bitrot stub */
887953
+#define CHANGELOG_OP_TYPE_MAX        (1<
887953
+
887953
+
887953
+struct ev_open {
887953
+        unsigned char gfid[16];
887953
+        int32_t flags;
887953
+};
887953
+
887953
+struct ev_creat {
887953
+        unsigned char gfid[16];
887953
+        int32_t flags;
887953
+};
887953
+
887953
+struct ev_release {
887953
+        unsigned char gfid[16];
887953
+};
887953
+
887953
+struct ev_release_br {
887953
+        unsigned long version;
887953
+        unsigned char gfid[16];
887953
+        int32_t sign_info;
887953
+};
887953
+
887953
+struct ev_changelog {
887953
+        char path[PATH_MAX];
887953
+};
887953
+
887953
+typedef struct changelog_event {
887953
+        unsigned int ev_type;
887953
+
887953
+        union {
887953
+                struct ev_open open;
887953
+                struct ev_creat create;
887953
+                struct ev_release release;
887953
+                struct ev_changelog journal;
887953
+                struct ev_release_br releasebr;
887953
+        } u;
887953
+} changelog_event_t;
887953
+
887953
+#define CHANGELOG_EV_SIZE  (sizeof (changelog_event_t))
887953
+
887953
+/**
887953
+ * event callback, connected & disconnection defs
887953
+ */
887953
+typedef void (CALLBACK) (void *, char *,
887953
+                        void *, changelog_event_t *);
887953
+typedef void *(INIT) (void *, struct gf_brick_spec *);
887953
+typedef void (FINI) (void *, char *, void *);
887953
+typedef void (CONNECT) (void *, char *, void *);
887953
+typedef void (DISCONNECT) (void *, char *, void *);
887953
+
887953
+struct gf_brick_spec {
887953
+        char         *brick_path;
887953
+        unsigned int  filter;
887953
+
887953
+        INIT       *init;
887953
+        FINI       *fini;
887953
+        CALLBACK   *callback;
887953
+        CONNECT    *connected;
887953
+        DISCONNECT *disconnected;
887953
+
887953
+        void *ptr;
887953
+};
887953
+
887953
+/* API set */
887953
+
887953
+int
887953
+gf_changelog_register (char *brick_path, char *scratch_dir,
887953
+                       char *log_file, int log_levl, int max_reconnects);
887953
+ssize_t
887953
+gf_changelog_scan ();
887953
+
887953
+int
887953
+gf_changelog_start_fresh ();
887953
+
887953
+ssize_t
887953
+gf_changelog_next_change (char *bufptr, size_t maxlen);
887953
+
887953
+int
887953
+gf_changelog_done (char *file);
887953
+
887953
+/* newer flexible API */
887953
+int
887953
+gf_changelog_init (void *xl);
887953
+
887953
+int
887953
+gf_changelog_register_generic (struct gf_brick_spec *bricks, int count,
887953
+                               int ordered, char *logfile, int lvl, void *xl);
887953
+
887953
+int
887953
+gf_history_changelog (char *changelog_dir, unsigned long start,
887953
+                      unsigned long end, int n_parallel,
887953
+                      unsigned long *actual_end);
887953
+#endif
887953
diff --git a/tests/utils/changelog/get-history.c b/tests/utils/changelog/get-history.c
887953
new file mode 100644
887953
index 0000000..29dc609
887953
--- /dev/null
887953
+++ b/tests/utils/changelog/get-history.c
887953
@@ -0,0 +1,73 @@
887953
+/*
887953
+   Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
887953
+   This file is part of GlusterFS.
887953
+
887953
+   This file is licensed to you under your choice of the GNU Lesser
887953
+   General Public License, version 3 or any later version (LGPLv3 or
887953
+   later), or the GNU General Public License, version 2 (GPLv2), in all
887953
+   cases as published by the Free Software Foundation.
887953
+*/
887953
+
887953
+/**
887953
+ * get set of new changes every 10 seconds (just print the file names)
887953
+ *
887953
+ * Compile it using:
887953
+ *  gcc -o gethistory `pkg-config --cflags libgfchangelog` get-history.c \
887953
+ *  `pkg-config --libs libgfchangelog`
887953
+ */
887953
+
887953
+#include <stdio.h>
887953
+#include <stdlib.h>
887953
+#include <unistd.h>
887953
+#include <sys/un.h>
887953
+#include <limits.h>
887953
+#include <sys/socket.h>
887953
+#include <sys/types.h>
887953
+
887953
+#include "changelog.h"
887953
+
887953
+int
887953
+main (int argc, char **argv)
887953
+{
887953
+        int     ret          = 0;
887953
+        unsigned long end_ts = 0;
887953
+        int start  = 0;
887953
+        int end    = 0;
887953
+
887953
+        ret = gf_changelog_init (NULL);
887953
+        if (ret) {
887953
+                printf ("-1");
887953
+                fflush(stdout);
887953
+                return -1;
887953
+        }
887953
+
887953
+        ret = gf_changelog_register ("/d/backends/patchy0",
887953
+                                     "/tmp/scratch_v1",
887953
+                                     "/var/log/glusterfs/changes.log",
887953
+                                     9, 5);
887953
+        if (ret) {
887953
+                printf ("-2");
887953
+                fflush(stdout);
887953
+                return -1;
887953
+        }
887953
+
887953
+        start = atoi(argv[1]);
887953
+        end = atoi(argv[2]);
887953
+
887953
+        ret = gf_history_changelog ("/d/backends/patchy0/.glusterfs/changelogs",
887953
+                                    start, end, 3, &end_ts);
887953
+        if (ret < 0) {
887953
+                printf ("-3");
887953
+                fflush(stdout);
887953
+                return -1;
887953
+        } else if (ret == 1) {
887953
+                printf ("1");
887953
+                fflush(stdout);
887953
+                return 0;
887953
+        }
887953
+
887953
+out:
887953
+        printf ("0");
887953
+        fflush(stdout);
887953
+        return 0;
887953
+}
887953
diff --git a/xlators/features/changelog/lib/src/gf-history-changelog.c b/xlators/features/changelog/lib/src/gf-history-changelog.c
887953
index 4355396..c1a7070 100644
887953
--- a/xlators/features/changelog/lib/src/gf-history-changelog.c
887953
+++ b/xlators/features/changelog/lib/src/gf-history-changelog.c
887953
@@ -772,6 +772,15 @@ gf_changelog_extract_min_max (const char *dname, const char *htime_dir,
887953
         return ret;
887953
 }
887953
 
887953
+/* gf_history_changelog returns actual_end and spawns threads to
887953
+ * parse historical changelogs. The return values are as follows.
887953
+ *     0 : On success
887953
+ *     1 : Successful, but partial historical changelogs available,
887953
+ *         end time falls into different htime file or future time
887953
+ *    -2 : Error, requested historical changelog not available, not
887953
+ *         even partial
887953
+ *    -1 : On any error
887953
+ */
887953
 int
887953
 gf_history_changelog (char* changelog_dir, unsigned long start,
887953
                       unsigned long end, int n_parallel,
887953
@@ -799,6 +808,7 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
887953
         pthread_t                       consume_th              = 0;
887953
         char                            htime_dir[PATH_MAX]     = {0,};
887953
         char                            buffer[PATH_MAX]        = {0,};
887953
+        gf_boolean_t                    partial_history         = _gf_false;
887953
 
887953
         pthread_attr_t attr;
887953
 
887953
@@ -828,6 +838,11 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
887953
                 goto out;
887953
         }
887953
 
887953
+        gf_smsg (this->name, GF_LOG_INFO, 0,
887953
+                 CHANGELOG_LIB_MSG_TOTAL_LOG_INFO,
887953
+                 "Requesting historical changelogs",
887953
+                 "start=%lu", start, "end=%lu", end, NULL);
887953
+
887953
         /* basic sanity check */
887953
         if (start > end || n_parallel <= 0) {
887953
                 gf_msg (this->name, GF_LOG_ERROR, errno,
887953
@@ -860,8 +875,14 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
887953
 
887953
                 entry = sys_readdir (dirp, scratch);
887953
 
887953
-                if (!entry || errno != 0)
887953
+                if (!entry || errno != 0) {
887953
+                        gf_smsg (this->name, GF_LOG_ERROR, errno,
887953
+                                 CHANGELOG_LIB_MSG_HIST_FAILED,
887953
+                                 "Requested changelog range is not availbale",
887953
+                                 "start=%lu", start, "end=%lu", end, NULL);
887953
+                        ret = -2;
887953
                         break;
887953
+                }
887953
 
887953
                 ret = gf_changelog_extract_min_max (entry->d_name, htime_dir,
887953
                                                     &fd, &total_changelog,
887953
@@ -906,6 +927,23 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
887953
 
887953
                         end2 = (end <= max_ts) ? end : max_ts;
887953
 
887953
+                        /* Check if end falls out of same HTIME file. The end
887953
+                         * falling to a different htime file or changelog
887953
+                         * disable-enable is detected only after 20 seconds.
887953
+                         * This is required because, applications generally
887953
+                         * asks historical changelogs till current time and
887953
+                         * it is possible changelog is not rolled over yet.
887953
+                         * So, buffer time of default rollover time plus 5
887953
+                         * seconds is subtracted.  If the application requests
887953
+                         * the end time with in half a minute of changelog
887953
+                         * disable, it's not detected as changelog disable and
887953
+                         * it's application's responsibility to retry after
887953
+                         * 20 seconds before confirming it as partial history.
887953
+                         */
887953
+                        if ((end - 20) > max_ts) {
887953
+                                partial_history = _gf_true;
887953
+                        }
887953
+
887953
                         /**
887953
                          * search @end2 in htime file returning it's index (@to)
887953
                          */
887953
@@ -972,12 +1010,15 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
887953
                         goto out;
887953
 
887953
                 } else {/* end of range check */
887953
-                        gf_msg (this->name, GF_LOG_ERROR, errno,
887953
-                        CHANGELOG_LIB_MSG_HIST_FAILED, "Requested changelog "
887953
-                        "range is not available. START - %lu CHLOG_MIN - %lu "
887953
-                        "CHLOG_MAX - %lu", start, min_ts, max_ts);
887953
-                        ret = -2;
887953
-                        goto out;
887953
+                        gf_smsg (this->name, GF_LOG_ERROR, errno,
887953
+                                 CHANGELOG_LIB_MSG_HIST_FAILED,
887953
+                                 "Requested changelog range is not "
887953
+                                 "available. Retrying next HTIME",
887953
+                                 "start=%lu", start,
887953
+                                 "end=%lu", end,
887953
+                                 "chlog_min=%lu", min_ts,
887953
+                                 "chlog_max=%lu", max_ts,
887953
+                                 NULL);
887953
                 }
887953
         } /* end of readdir() */
887953
 
887953
@@ -1000,5 +1041,9 @@ out:
887953
         hist_jnl->hist_done = 1;
887953
         *actual_end = ts2;
887953
 
887953
+        if (partial_history) {
887953
+                ret = 1;
887953
+        }
887953
+
887953
         return ret;
887953
 }
887953
-- 
887953
1.8.3.1
887953