diff options
author | Kotresh H R <khiremat@redhat.com> | 2014-08-01 16:12:38 +0530 |
---|---|---|
committer | Vijay Bellur <vbellur@redhat.com> | 2014-08-04 07:51:07 -0700 |
commit | 0e8c537d6f48857b0f3c0ef10ce1c4458e303be8 (patch) | |
tree | 5a41d0e21b186d2c8d8589a5542930fcbb2fb0fe | |
parent | 51394183e94ac0be70fcf22793b2040ba3f0b918 (diff) |
feature/geo-rep: Keep marker.tstamp's mtime unchangeable during snapshot.
Problem:
Geo-replicatoin does a full xsync crawl after snapshot
restoration of slave and master. It does not do history crawl.
Analysis:
Marker creates 'marker.tstamp' file when geo-rep is started
for the first time. The virtual extended attribute
'trusted.glusterfs.volume-mark' is maintained and whenever
it is queried on gluster mount point, marker fills it on
the fly and returns the combination of uuid, ctime of
marker.tstamp and others. So ctime of marker.tstamp, in other
sense 'volume-mark' marks the geo-rep start time when the
session is freshly created.
From the above, after the first filesystem crawl(xsync) is
done during first geo-rep start, stime should always be less
than 'volume-mark'. So whenever stime is less than volume-mark,
it does full filesystem crawl (xsync).
Root Cause:
When snapshot is restored, marker.tstamp file is freshly
created losing the timestamps, it was originally created with.
Solution:
1. Change is made to depend on mtime instead of ctime.
2. mtime and atime of marker.tstamp is restored back when
snapshot is created and restored.
Change-Id: I4891b112f4aedc50cfae402832c50c5145807d7a
BUG: 1125918
Signed-off-by: Kotresh H R <khiremat@redhat.com>
Reviewed-on: http://review.gluster.org/8401
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
-rw-r--r-- | libglusterfs/src/common-utils.c | 43 | ||||
-rw-r--r-- | libglusterfs/src/common-utils.h | 1 | ||||
-rw-r--r-- | xlators/features/marker/src/marker.c | 4 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.c | 69 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 65 |
5 files changed, 169 insertions, 13 deletions
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 54ee3e53818..be8bd6298ac 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -3232,3 +3232,46 @@ gf_compare_sockaddr (const struct sockaddr *addr1, } return _gf_false; } + +/* + * gf_set_timestamp: + * It sets the mtime and atime of 'dest' file as of 'src'. + */ + +int +gf_set_timestamp (const char *src, const char* dest) +{ + struct stat sb = {0, }; + struct timeval new_time[2] = {{0, },{0,}}; + int ret = 0; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (src); + GF_ASSERT (dest); + + ret = stat (src, &sb); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "stat on %s failed: %s", + src, strerror(errno)); + goto out; + } + new_time[0].tv_sec = sb.st_atime; + new_time[0].tv_usec = ST_ATIM_NSEC (&sb)/1000; + + new_time[1].tv_sec = sb.st_mtime; + new_time[1].tv_usec = ST_MTIM_NSEC (&sb)/1000; + + /* The granularity is micro seconds as per the current + * requiremnt. Hence using 'utimes'. This can be updated + * to 'utimensat' if we need timestamp in nanoseconds. + */ + ret = utimes (dest, new_time); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "utimes on %s failed: %s", + dest, strerror(errno)); + } +out: + return ret; +} diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index 98f30fc47b0..4eec5170c60 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -620,6 +620,7 @@ int gf_get_hostname_from_ip (char *client_ip, char **hostname); gf_boolean_t gf_is_local_addr (char *hostname); gf_boolean_t gf_is_same_address (char *host1, char *host2); void md5_wrapper(const unsigned char *data, size_t len, char *md5); +int gf_set_timestamp (const char *src, const char* dest); int gf_thread_create (pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg); diff --git a/xlators/features/marker/src/marker.c b/xlators/features/marker/src/marker.c index a92c57dac1e..e9a8e544b3b 100644 --- a/xlators/features/marker/src/marker.c +++ b/xlators/features/marker/src/marker.c @@ -216,8 +216,8 @@ stat_stampfile (xlator_t *this, marker_conf_t *priv, if (stat (priv->timestamp_file, &buf) != -1) { vol_mark->retval = 0; - vol_mark->sec = htonl (buf.st_ctime); - vol_mark->usec = htonl (ST_CTIM_NSEC (&buf)/1000); + vol_mark->sec = htonl (buf.st_mtime); + vol_mark->usec = htonl (ST_MTIM_NSEC (&buf)/1000); } else vol_mark->retval = 1; diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index ee3759e91d4..8b9b4b1a018 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -621,6 +621,62 @@ out: return ret; } +/* + * glusterd_snap_geo_rep_restore: + * This function restores the atime and mtime of marker.tstamp + * if present from snapped marker.tstamp file. + */ +static int +glusterd_snap_geo_rep_restore (glusterd_volinfo_t *snap_volinfo, + glusterd_volinfo_t *new_volinfo) +{ + char vol_tstamp_file[PATH_MAX] = {0,}; + char snap_tstamp_file[PATH_MAX] = {0,}; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + int geo_rep_indexing_on = 0; + int ret = 0; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (snap_volinfo); + GF_ASSERT (new_volinfo); + + priv = this->private; + GF_ASSERT (priv); + + /* Check if geo-rep indexing is enabled, if yes, we need restore + * back the mtime of 'marker.tstamp' file. + */ + geo_rep_indexing_on = glusterd_volinfo_get_boolean (new_volinfo, + VKEY_MARKER_XTIME); + if (geo_rep_indexing_on == -1) { + gf_log (this->name, GF_LOG_DEBUG, "Failed" + " to check whether geo-rep-indexing enabled or not"); + ret = 0; + goto out; + } + + if (geo_rep_indexing_on == 1) { + GLUSTERD_GET_VOLUME_DIR (vol_tstamp_file, new_volinfo, priv); + strncat (vol_tstamp_file, "/marker.tstamp", + PATH_MAX - strlen(vol_tstamp_file) - 1); + GLUSTERD_GET_VOLUME_DIR (snap_tstamp_file, snap_volinfo, priv); + strncat (snap_tstamp_file, "/marker.tstamp", + PATH_MAX - strlen(snap_tstamp_file) - 1); + ret = gf_set_timestamp (snap_tstamp_file, vol_tstamp_file); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set atime and mtime of %s as of %s", + vol_tstamp_file, snap_tstamp_file); + goto out; + } + } + +out: + return ret; +} + /* This function will copy snap volinfo to the new * passed volinfo and regenerate backend store files * for the restored snap. @@ -760,6 +816,19 @@ glusterd_snap_volinfo_restore (dict_t *dict, dict_t *rsp_dict, /* Regenerate all volfiles */ ret = glusterd_create_volfiles_and_notify_services (new_volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to regenerate volfiles"); + goto out; + } + + /* Restore geo-rep marker.tstamp's timestamp */ + ret = glusterd_snap_geo_rep_restore (snap_volinfo, new_volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Geo-rep: marker.tstamp's timestamp restoration failed"); + goto out; + } out: if (ret && (NULL != new_brickinfo)) { diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 9701c6b939c..f1e30e1ee82 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -16,6 +16,7 @@ #include <fnmatch.h> #include <sys/wait.h> #include <dlfcn.h> +#include <utime.h> #if (HAVE_LIB_XML) #include <libxml/encoding.h> @@ -3824,12 +3825,34 @@ get_vol_tstamp_file (char *filename, glusterd_volinfo_t *volinfo) PATH_MAX - strlen(filename) - 1); } +static void +get_parent_vol_tstamp_file (char *filename, glusterd_volinfo_t *volinfo) +{ + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + snprintf (filename, PATH_MAX, "%s/vols/%s", priv->workdir, + volinfo->parent_volname); + strncat (filename, "/marker.tstamp", + PATH_MAX - strlen(filename) - 1); +} + int generate_brick_volfiles (glusterd_volinfo_t *volinfo) { - glusterd_brickinfo_t *brickinfo = NULL; - char tstamp_file[PATH_MAX] = {0,}; - int ret = -1; + glusterd_brickinfo_t *brickinfo = NULL; + char tstamp_file[PATH_MAX] = {0,}; + char parent_tstamp_file[PATH_MAX] = {0,}; + int ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); ret = glusterd_volinfo_get_boolean (volinfo, VKEY_MARKER_XTIME); if (ret == -1) @@ -3840,29 +3863,49 @@ generate_brick_volfiles (glusterd_volinfo_t *volinfo) if (ret) { ret = open (tstamp_file, O_WRONLY|O_CREAT|O_EXCL, 0600); if (ret == -1 && errno == EEXIST) { - gf_log ("", GF_LOG_DEBUG, "timestamp file exist"); + gf_log (this->name, GF_LOG_DEBUG, + "timestamp file exist"); ret = -2; } if (ret == -1) { - gf_log ("", GF_LOG_ERROR, "failed to create %s (%s)", - tstamp_file, strerror (errno)); + gf_log (this->name, GF_LOG_ERROR, "failed to create " + "%s (%s)", tstamp_file, strerror (errno)); return -1; } - if (ret >= 0) + if (ret >= 0) { close (ret); + /* If snap_volume, retain timestamp for marker.tstamp + * from parent. Geo-replication depends on mtime of + * 'marker.tstamp' to decide the volume-mark, i.e., + * geo-rep start time just after session is created. + */ + if (volinfo->is_snap_volume) { + get_parent_vol_tstamp_file (parent_tstamp_file, + volinfo); + ret = gf_set_timestamp (parent_tstamp_file, + tstamp_file); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set atime and mtime" + " of %s as of %s", tstamp_file, + parent_tstamp_file); + goto out; + } + } + } } else { ret = unlink (tstamp_file); if (ret == -1 && errno == ENOENT) ret = 0; if (ret == -1) { - gf_log ("", GF_LOG_ERROR, "failed to unlink %s (%s)", - tstamp_file, strerror (errno)); + gf_log (this->name, GF_LOG_ERROR, "failed to unlink " + "%s (%s)", tstamp_file, strerror (errno)); return -1; } } list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - gf_log ("", GF_LOG_DEBUG, + gf_log (this->name, GF_LOG_DEBUG, "Found a brick - %s:%s", brickinfo->hostname, brickinfo->path); @@ -3875,7 +3918,7 @@ generate_brick_volfiles (glusterd_volinfo_t *volinfo) ret = 0; out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } |