diff options
| -rw-r--r-- | tests/basic/changelog/changelog-history.t | 86 | ||||
| -rw-r--r-- | tests/utils/changelog/changelog.h | 120 | ||||
| -rw-r--r-- | tests/utils/changelog/get-history.c | 73 | ||||
| -rw-r--r-- | xlators/features/changelog/lib/src/gf-history-changelog.c | 51 | 
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;  }  | 
