summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/basic/changelog/changelog-history.t86
-rw-r--r--tests/utils/changelog/changelog.h120
-rw-r--r--tests/utils/changelog/get-history.c73
-rw-r--r--xlators/features/changelog/lib/src/gf-history-changelog.c51
4 files changed, 325 insertions, 5 deletions
diff --git a/tests/basic/changelog/changelog-history.t b/tests/basic/changelog/changelog-history.t
new file mode 100644
index 00000000000..3ce40981c90
--- /dev/null
+++ b/tests/basic/changelog/changelog-history.t
@@ -0,0 +1,86 @@
+#!/bin/bash
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+. $(dirname $0)/../../env.rc
+
+cleanup;
+
+HISTORY_BIN_PATH=$(dirname $0)/../../utils/changelog
+build_tester $HISTORY_BIN_PATH/get-history.c -lgfchangelog
+
+time_before_enable1=$(date '+%s')
+CHANGELOG_PATH_0="$B0/${V0}0/.glusterfs/changelogs"
+ROLLOVER_TIME=2
+
+TEST glusterd
+TEST pidof glusterd
+
+sleep 3
+time_before_enable2=$(date '+%s')
+
+sleep 3
+TEST $CLI volume create $V0 $H0:$B0/${V0}0
+TEST $CLI volume set $V0 changelog.changelog on
+TEST $CLI volume set $V0 changelog.rollover-time $ROLLOVER_TIME
+TEST $CLI volume start $V0
+
+sleep 3
+time_after_enable1=$(date '+%s')
+
+TEST $GFS --volfile-id=$V0 --volfile-server=$H0 $M0;
+touch $M0/file{1..10}
+
+sleep 3
+time_after_enable2=$(date '+%s')
+
+let time_future=time_after_enable2+600
+
+#Fails as start falls before changelog enable
+EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_before_enable1 $time_before_enable2
+
+#Fails as start falls before changelog enable
+EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_before_enable2 $time_after_enable1
+
+#Passes as start and end falls in same htime file
+EXPECT "0" $HISTORY_BIN_PATH/get-history $time_after_enable1 $time_after_enable2
+
+#Passes, gives the changelogs till continuous changelogs are available
+# but returns 1
+EXPECT "1" $HISTORY_BIN_PATH/get-history $time_after_enable2 $time_future
+
+#Disable and enable changelog
+TEST $CLI volume set $V0 changelog.changelog off
+sleep 6
+time_between_htime=$(date '+%s')
+sleep 6
+TEST $CLI volume set $V0 changelog.changelog on
+
+sleep 6
+touch $M0/test{1..10}
+time_in_sec_htime1=$(date '+%s')
+
+sleep 6
+touch $M0/test1{1..10}
+time_in_sec_htime2=$(date '+%s')
+
+sleep 3
+TEST $CLI volume set $V0 changelog.changelog off
+sleep 3
+time_after_disable=$(date '+%s')
+
+#Passes, gives the changelogs till continuous changelogs are available
+# but returns 1
+EXPECT "1" $HISTORY_BIN_PATH/get-history $time_after_enable1 $time_in_sec_htime2
+
+#Fails as start falls between htime files
+EXPECT "-3" $HISTORY_BIN_PATH/get-history $time_between_htime $time_in_sec_htime1
+
+#Passes as start and end falls in same htime file
+EXPECT "0" $HISTORY_BIN_PATH/get-history $time_in_sec_htime1 $time_in_sec_htime2
+
+#Passes, gives the changelogs till continuous changelogs are available
+EXPECT "0" $HISTORY_BIN_PATH/get-history $time_in_sec_htime2 $time_after_disable
+
+TEST rm $HISTORY_BIN_PATH/get-history
+
+cleanup;
diff --git a/tests/utils/changelog/changelog.h b/tests/utils/changelog/changelog.h
new file mode 100644
index 00000000000..14094cf3681
--- /dev/null
+++ b/tests/utils/changelog/changelog.h
@@ -0,0 +1,120 @@
+/*
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#ifndef _GF_CHANGELOG_H
+#define _GF_CHANGELOG_H
+
+struct gf_brick_spec;
+
+/**
+ * Max bit shiter for event selection
+ */
+#define CHANGELOG_EV_SELECTION_RANGE 5
+
+#define CHANGELOG_OP_TYPE_JOURNAL (1<<0)
+#define CHANGELOG_OP_TYPE_OPEN (1<<1)
+#define CHANGELOG_OP_TYPE_CREATE (1<<2)
+#define CHANGELOG_OP_TYPE_RELEASE (1<<3)
+#define CHANGELOG_OP_TYPE_BR_RELEASE (1<<4) /* logical release (last close()),
+ sent by bitrot stub */
+#define CHANGELOG_OP_TYPE_MAX (1<<CHANGELOG_EV_SELECTION_RANGE)
+
+
+struct ev_open {
+ unsigned char gfid[16];
+ int32_t flags;
+};
+
+struct ev_creat {
+ unsigned char gfid[16];
+ int32_t flags;
+};
+
+struct ev_release {
+ unsigned char gfid[16];
+};
+
+struct ev_release_br {
+ unsigned long version;
+ unsigned char gfid[16];
+ int32_t sign_info;
+};
+
+struct ev_changelog {
+ char path[PATH_MAX];
+};
+
+typedef struct changelog_event {
+ unsigned int ev_type;
+
+ union {
+ struct ev_open open;
+ struct ev_creat create;
+ struct ev_release release;
+ struct ev_changelog journal;
+ struct ev_release_br releasebr;
+ } u;
+} changelog_event_t;
+
+#define CHANGELOG_EV_SIZE (sizeof (changelog_event_t))
+
+/**
+ * event callback, connected & disconnection defs
+ */
+typedef void (CALLBACK) (void *, char *,
+ void *, changelog_event_t *);
+typedef void *(INIT) (void *, struct gf_brick_spec *);
+typedef void (FINI) (void *, char *, void *);
+typedef void (CONNECT) (void *, char *, void *);
+typedef void (DISCONNECT) (void *, char *, void *);
+
+struct gf_brick_spec {
+ char *brick_path;
+ unsigned int filter;
+
+ INIT *init;
+ FINI *fini;
+ CALLBACK *callback;
+ CONNECT *connected;
+ DISCONNECT *disconnected;
+
+ void *ptr;
+};
+
+/* API set */
+
+int
+gf_changelog_register (char *brick_path, char *scratch_dir,
+ char *log_file, int log_levl, int max_reconnects);
+ssize_t
+gf_changelog_scan ();
+
+int
+gf_changelog_start_fresh ();
+
+ssize_t
+gf_changelog_next_change (char *bufptr, size_t maxlen);
+
+int
+gf_changelog_done (char *file);
+
+/* newer flexible API */
+int
+gf_changelog_init (void *xl);
+
+int
+gf_changelog_register_generic (struct gf_brick_spec *bricks, int count,
+ int ordered, char *logfile, int lvl, void *xl);
+
+int
+gf_history_changelog (char *changelog_dir, unsigned long start,
+ unsigned long end, int n_parallel,
+ unsigned long *actual_end);
+#endif
diff --git a/tests/utils/changelog/get-history.c b/tests/utils/changelog/get-history.c
new file mode 100644
index 00000000000..29dc60987ae
--- /dev/null
+++ b/tests/utils/changelog/get-history.c
@@ -0,0 +1,73 @@
+/*
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+/**
+ * get set of new changes every 10 seconds (just print the file names)
+ *
+ * Compile it using:
+ * gcc -o gethistory `pkg-config --cflags libgfchangelog` get-history.c \
+ * `pkg-config --libs libgfchangelog`
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "changelog.h"
+
+int
+main (int argc, char **argv)
+{
+ int ret = 0;
+ unsigned long end_ts = 0;
+ int start = 0;
+ int end = 0;
+
+ ret = gf_changelog_init (NULL);
+ if (ret) {
+ printf ("-1");
+ fflush(stdout);
+ return -1;
+ }
+
+ ret = gf_changelog_register ("/d/backends/patchy0",
+ "/tmp/scratch_v1",
+ "/var/log/glusterfs/changes.log",
+ 9, 5);
+ if (ret) {
+ printf ("-2");
+ fflush(stdout);
+ return -1;
+ }
+
+ start = atoi(argv[1]);
+ end = atoi(argv[2]);
+
+ ret = gf_history_changelog ("/d/backends/patchy0/.glusterfs/changelogs",
+ start, end, 3, &end_ts);
+ if (ret < 0) {
+ printf ("-3");
+ fflush(stdout);
+ return -1;
+ } else if (ret == 1) {
+ printf ("1");
+ fflush(stdout);
+ return 0;
+ }
+
+out:
+ printf ("0");
+ fflush(stdout);
+ return 0;
+}
diff --git a/xlators/features/changelog/lib/src/gf-history-changelog.c b/xlators/features/changelog/lib/src/gf-history-changelog.c
index fd92dd7ed0b..5259ae3893b 100644
--- a/xlators/features/changelog/lib/src/gf-history-changelog.c
+++ b/xlators/features/changelog/lib/src/gf-history-changelog.c
@@ -780,6 +780,15 @@ gf_changelog_extract_min_max (const char *dname, const char *htime_dir,
return ret;
}
+/* gf_history_changelog returns actual_end and spawns threads to
+ * parse historical changelogs. The return values are as follows.
+ * 0 : On success
+ * 1 : Successful, but partial historical changelogs available,
+ * end time falls into different htime file or future time
+ * -2 : Error, requested historical changelog not available, not
+ * even partial
+ * -1 : On any error
+ */
int
gf_history_changelog (char* changelog_dir, unsigned long start,
unsigned long end, int n_parallel,
@@ -807,6 +816,7 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
pthread_t consume_th = 0;
char htime_dir[PATH_MAX] = {0,};
char buffer[PATH_MAX] = {0,};
+ gf_boolean_t partial_history = _gf_false;
pthread_attr_t attr;
@@ -836,6 +846,11 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
goto out;
}
+ gf_smsg (this->name, GF_LOG_INFO, 0,
+ CHANGELOG_LIB_MSG_TOTAL_LOG_INFO,
+ "Requesting historical changelogs",
+ "start=%lu", start, "end=%lu", end, NULL);
+
/* basic sanity check */
if (start > end || n_parallel <= 0) {
gf_smsg (this->name, GF_LOG_ERROR, errno,
@@ -871,8 +886,14 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
entry = sys_readdir (dirp, scratch);
- if (!entry || errno != 0)
+ if (!entry || errno != 0) {
+ gf_smsg (this->name, GF_LOG_ERROR, errno,
+ CHANGELOG_LIB_MSG_HIST_FAILED,
+ "Requested changelog range is not availbale",
+ "start=%lu", start, "end=%lu", end, NULL);
+ ret = -2;
break;
+ }
ret = gf_changelog_extract_min_max (entry->d_name, htime_dir,
&fd, &total_changelog,
@@ -919,6 +940,23 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
end2 = (end <= max_ts) ? end : max_ts;
+ /* Check if end falls out of same HTIME file. The end
+ * falling to a different htime file or changelog
+ * disable-enable is detected only after 20 seconds.
+ * This is required because, applications generally
+ * asks historical changelogs till current time and
+ * it is possible changelog is not rolled over yet.
+ * So, buffer time of default rollover time plus 5
+ * seconds is subtracted. If the application requests
+ * the end time with in half a minute of changelog
+ * disable, it's not detected as changelog disable and
+ * it's application's responsibility to retry after
+ * 20 seconds before confirming it as partial history.
+ */
+ if ((end - 20) > max_ts) {
+ partial_history = _gf_true;
+ }
+
/**
* search @end2 in htime file returning it's index (@to)
*/
@@ -992,14 +1030,13 @@ gf_history_changelog (char* changelog_dir, unsigned long start,
} else {/* end of range check */
gf_smsg (this->name, GF_LOG_ERROR, errno,
CHANGELOG_LIB_MSG_HIST_FAILED,
- "Requested changelog "
- "range is not available.",
+ "Requested changelog range is not "
+ "available. Retrying next HTIME",
"start=%lu", start,
+ "end=%lu", end,
"chlog_min=%lu", min_ts,
"chlog_max=%lu", max_ts,
NULL);
- ret = -2;
- goto out;
}
} /* end of readdir() */
@@ -1019,5 +1056,9 @@ out:
hist_jnl->hist_done = 1;
*actual_end = ts2;
+ if (partial_history) {
+ ret = 1;
+ }
+
return ret;
}