diff options
Diffstat (limited to 'xlators/lib/src/libxlator.c')
| -rw-r--r-- | xlators/lib/src/libxlator.c | 479 |
1 files changed, 269 insertions, 210 deletions
diff --git a/xlators/lib/src/libxlator.c b/xlators/lib/src/libxlator.c index df302d11d..9e5357255 100644 --- a/xlators/lib/src/libxlator.c +++ b/xlators/lib/src/libxlator.c @@ -1,7 +1,44 @@ +/* + Copyright (c) 2008-2012 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. +*/ #include "mem-types.h" #include "libxlator.h" +int marker_xtime_default_gauge[] = { + [MCNT_FOUND] = 1, + [MCNT_NOTFOUND] = -1, + [MCNT_ENODATA] = -1, + [MCNT_ENOTCONN] = -1, + [MCNT_ENOENT] = -1, + [MCNT_EOTHER] = -1, +}; + +int marker_uuid_default_gauge[] = { + [MCNT_FOUND] = 1, + [MCNT_NOTFOUND] = 0, + [MCNT_ENODATA] = 0, + [MCNT_ENOTCONN] = 0, + [MCNT_ENOENT] = 0, + [MCNT_EOTHER] = 0, +}; + +static int marker_idx_errno_map[] = { + [MCNT_FOUND] = EINVAL, + [MCNT_NOTFOUND] = EINVAL, + [MCNT_ENOENT] = ENOENT, + [MCNT_ENOTCONN] = ENOTCONN, + [MCNT_ENODATA] = ENODATA, + [MCNT_EOTHER] = EINVAL, + [MCNT_MAX] = 0, +}; + /*Copy the contents of oldtimebuf to newtimbuf*/ static void update_timebuf (uint32_t *oldtimbuf, uint32_t *newtimebuf) @@ -35,139 +72,148 @@ match_uuid_local (const char *name, char *uuid) return 0; } +static void +marker_local_incr_errcount (xl_marker_local_t *local, int op_errno) +{ + marker_result_idx_t i = -1; + if (!local) + return; + + switch (op_errno) { + case ENODATA: + i = MCNT_ENODATA; + break; + case ENOENT: + i = MCNT_ENOENT; + break; + case ENOTCONN: + i = MCNT_ENOTCONN; + break; + default: + i = MCNT_EOTHER; + break; + } + local->count[i]++; +} + +static int +evaluate_marker_results (int *gauge, int *count) +{ + int i = 0; + int op_errno = 0; + gf_boolean_t sane = _gf_true; + + /* check if the policy of the gauge is violated; + * if yes, try to get the best errno, ie. look + * for the first position where there is a more + * specific kind of vioilation than the generic EINVAL + */ + for (i = 0; i < MCNT_MAX; i++) { + if (sane) { + if ((gauge[i] > 0 && count[i] < gauge[i]) || + (gauge[i] < 0 && count[i] >= -gauge[i])) { + sane = _gf_false; + /* generic action: adopt corresponding errno */ + op_errno = marker_idx_errno_map[i]; + } + } else { + /* already insane; trying to get a more informative + * errno by checking subsequent counters + */ + if (count[i] > 0) + op_errno = marker_idx_errno_map[i]; + } + if (op_errno && op_errno != EINVAL) + break; + } + + return op_errno; +} /* Aggregate all the <volid>.xtime attrs of the cluster and send the max*/ int32_t cluster_markerxtime_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int op_ret, int op_errno, dict_t *dict) + int op_ret, int op_errno, dict_t *dict, dict_t *xdata) { - int32_t callcnt = 0; - int ret = -1; - uint32_t *net_timebuf = NULL; - uint32_t host_timebuf[2] = {0,}; - char *marker_xattr = NULL; - struct marker_str *local = NULL; - char *vol_uuid = NULL; + int32_t callcnt = 0; + int ret = -1; + uint32_t *net_timebuf = NULL; + uint32_t host_timebuf[2] = {0,}; + char *marker_xattr = NULL; + xl_marker_local_t *local = NULL; + char *vol_uuid = NULL; + char need_unwind = 0; if (!this || !frame || !frame->local || !cookie) { - gf_log (this->name, GF_LOG_DEBUG, "possible NULL deref"); + gf_log ("", GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; goto out; } local = frame->local; if (!local || !local->vol_uuid) { gf_log (this->name, GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; goto out; } - if (local->esomerr) { - LOCK (&frame->lock); - { - callcnt = --local->call_count; - } - goto done; - } - - vol_uuid = local->vol_uuid; - - if (op_ret && op_errno == ENODATA) { - LOCK (&frame->lock); - { - callcnt = --local->call_count; - local->enodata_count++; - } - goto done; - } + LOCK (&frame->lock); + { + callcnt = --local->call_count; - if (op_ret && op_errno == ENOENT) { - LOCK (&frame->lock); - { - callcnt = --local->call_count; - local->enoent_count++; - } - goto done; - } + vol_uuid = local->vol_uuid; - if (op_ret && op_errno == ENOTCONN) { - LOCK (&frame->lock); - { - callcnt = --local->call_count; - local->enotconn_count++; + if (op_ret) { + marker_local_incr_errcount (local, op_errno); + goto unlock; } - goto done; - } - if (op_ret) { - LOCK (&frame->lock); - { - callcnt = --local->call_count; - local->esomerr = op_errno; - } - goto done; - } - - - - - LOCK (&frame->lock); - { - callcnt = --local->call_count; - if (!gf_asprintf (& marker_xattr, "%s.%s.%s", + if (!gf_asprintf (&marker_xattr, "%s.%s.%s", MARKER_XATTR_PREFIX, vol_uuid, XTIME)) { op_errno = ENOMEM; - goto done; + goto unlock; } if (dict_get_ptr (dict, marker_xattr, (void **)&net_timebuf)) { gf_log (this->name, GF_LOG_WARNING, "Unable to get <uuid>.xtime attr"); - local->noxtime_count++; - goto done; + local->count[MCNT_NOTFOUND]++; + goto unlock; } - if (local->has_xtime) { - + if (local->count[MCNT_FOUND]) { get_hosttime (net_timebuf, host_timebuf); if ( (host_timebuf[0]>local->host_timebuf[0]) || (host_timebuf[0] == local->host_timebuf[0] && host_timebuf[1] >= local->host_timebuf[1])) { - update_timebuf (net_timebuf, local->net_timebuf); update_timebuf (host_timebuf, local->host_timebuf); - } - } - else { + } else { get_hosttime (net_timebuf, local->host_timebuf); update_timebuf (net_timebuf, local->net_timebuf); - local->has_xtime = _gf_true; + local->count[MCNT_FOUND]++; } - - } -done: +unlock: UNLOCK (&frame->lock); if (!callcnt) { - op_ret = 0; op_errno = 0; - if (local->has_xtime) { - if (!dict) { + need_unwind = 1; + + if (local->count[MCNT_FOUND]) { + if (!dict) dict = dict_new(); - if (ret) { - op_ret = -1; - op_errno = ENOMEM; - goto out; - } - } + ret = dict_set_static_bin (dict, marker_xattr, (void *)local->net_timebuf, 8); if (ret) { @@ -175,178 +221,133 @@ done: op_errno = ENOMEM; goto out; } - goto out; } - if (local->noxtime_count) - goto out; - - if (local->enodata_count) { - op_ret = -1; - op_errno = ENODATA; - goto out; - } - if (local->enotconn_count) { - op_ret = -1; - op_errno = ENOTCONN; - goto out; - } - if (local->enoent_count) { + op_errno = evaluate_marker_results (local->gauge, local->count); + if (op_errno) op_ret = -1; - op_errno = ENOENT; - goto out; - } - else { - op_errno = local->esomerr; - goto out; - } -out: - if (local->xl_specf_unwind) { - frame->local = local->xl_local; - local->xl_specf_unwind (frame, op_ret, - op_errno, dict); - return 0; - } - STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, dict); + } +out: + if (need_unwind && local && local->xl_specf_unwind) { + frame->local = local->xl_local; + local->xl_specf_unwind (frame, op_ret, + op_errno, dict, xdata); + } else if (need_unwind) { + STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, + dict, xdata); } + GF_FREE (marker_xattr); return 0; } int32_t cluster_markeruuid_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int op_ret, int op_errno, dict_t *dict) + int op_ret, int op_errno, dict_t *dict, dict_t *xdata) { - int32_t callcnt = 0; - data_t *data = NULL; - struct volume_mark *volmark = NULL; - struct marker_str *marker = NULL; - char *vol_uuid; + int32_t callcnt = 0; + struct volume_mark *volmark = NULL; + xl_marker_local_t *local = NULL; + int32_t ret = -1; + char need_unwind = 0; + char *vol_uuid = NULL; if (!this || !frame || !cookie) { - gf_log (this->name, GF_LOG_DEBUG, "possible NULL deref"); + gf_log ("", GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; goto out; } - marker = frame->local; + local = frame->local; - if (!marker) { + if (!local) { gf_log (this->name, GF_LOG_DEBUG, "possible NULL deref"); + need_unwind = 1; goto out; } - vol_uuid = marker->vol_uuid; - - if (op_ret && (ENOENT == op_errno)) { - LOCK (&frame->lock); - { - callcnt = --marker->call_count; - marker->enoent_count++; - } - goto done; - } - - if (op_ret && (ENOTCONN == op_errno)) { - LOCK (&frame->lock); - { - callcnt = --marker->call_count; - marker->enotconn_count++; - } - goto done; - } - - if (!(data = dict_get (dict, GF_XATTR_MARKER_KEY))) { - LOCK (&frame->lock); - { - callcnt = --marker->call_count; - } - goto done; - } - - volmark = (struct volume_mark *)data->data; - LOCK (&frame->lock); { - callcnt = --marker->call_count; + callcnt = --local->call_count; + vol_uuid = local->vol_uuid; - if (marker_has_volinfo (marker)) { + if (op_ret) { + marker_local_incr_errcount (local, op_errno); + goto unlock; + } + + ret = dict_get_bin (dict, GF_XATTR_MARKER_KEY, + (void *)&volmark); + if (ret) + goto unlock; - if ((marker->volmark->major != volmark->major) || - (marker->volmark->minor != volmark->minor)) { + if (local->count[MCNT_FOUND]) { + if ((local->volmark->major != volmark->major) || + (local->volmark->minor != volmark->minor)) { op_ret = -1; op_errno = EINVAL; - goto done; - } - else if (volmark->retval) { - data_unref ((data_t *) marker->volmark); - marker->volmark = volmark; - callcnt = 0; + goto unlock; } - else if ( (volmark->sec > marker->volmark->sec) || - ((volmark->sec == marker->volmark->sec) - && (volmark->usec >= marker->volmark->usec))) { - GF_FREE (marker->volmark); - marker->volmark = memdup (volmark, sizeof (struct volume_mark)); - VALIDATE_OR_GOTO (marker->volmark, done); + if (local->retval) + goto unlock; + else if (volmark->retval) { + GF_FREE (local->volmark); + local->volmark = + memdup (volmark, sizeof (*volmark)); + local->retval = volmark->retval; + } else if ((volmark->sec > local->volmark->sec) || + ((volmark->sec == local->volmark->sec) && + (volmark->usec >= local->volmark->usec))) { + GF_FREE (local->volmark); + local->volmark = + memdup (volmark, sizeof (*volmark)); } } else { - marker->volmark = memdup (volmark, sizeof (struct volume_mark)); - VALIDATE_OR_GOTO (marker->volmark, done); - + local->volmark = memdup (volmark, sizeof (*volmark)); + VALIDATE_OR_GOTO (local->volmark, unlock); uuid_unparse (volmark->uuid, vol_uuid); if (volmark->retval) - callcnt = 0; + local->retval = volmark->retval; + local->count[MCNT_FOUND]++; } } -done: +unlock: UNLOCK (&frame->lock); if (!callcnt) { op_ret = 0; op_errno = 0; - if (marker_has_volinfo (marker)) { - if (!dict) { + need_unwind = 1; + + if (local->count[MCNT_FOUND]) { + if (!dict) dict = dict_new(); - if (!dict) { - op_ret = -1; - op_errno = ENOMEM; - goto out; - } - } + if (dict_set_bin (dict, GF_XATTR_MARKER_KEY, - marker->volmark, + local->volmark, sizeof (struct volume_mark))) { op_ret = -1; op_errno = ENOMEM; } - goto out; - } - if (marker->enotconn_count) { - op_ret = -1; - op_errno = ENOTCONN; - goto out; - } - if (marker->enoent_count) { - op_ret = -1; - op_errno = ENOENT; } - else { + op_errno = evaluate_marker_results (local->gauge, local->count); + if (op_errno) op_ret = -1; - op_errno = EINVAL; - } + } out: - if (marker->xl_specf_unwind) { - frame->local = marker->xl_local; - marker->xl_specf_unwind (frame, op_ret, - op_errno, dict); - return 0; - } - STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, dict); + if (need_unwind && local && local->xl_specf_unwind) { + frame->local = local->xl_local; + local->xl_specf_unwind (frame, op_ret, + op_errno, dict, xdata); + return 0; + } else if (need_unwind){ + STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, + dict, xdata); } return 0; } @@ -357,10 +358,10 @@ cluster_getmarkerattr (call_frame_t *frame,xlator_t *this, loc_t *loc, const char *name, void *xl_local, xlator_specf_unwind_t xl_specf_getxattr_unwind, xlator_t **sub_volumes, int count, int type, - char *vol_uuid) + int *gauge, char *vol_uuid) { - int i; - struct marker_str *local; + int i = 0; + xl_marker_local_t *local = NULL; VALIDATE_OR_GOTO (frame, err); VALIDATE_OR_GOTO (this, err); @@ -373,33 +374,36 @@ cluster_getmarkerattr (call_frame_t *frame,xlator_t *this, loc_t *loc, local = GF_CALLOC (sizeof (struct marker_str), 1, gf_common_mt_libxl_marker_local); - local->xl_local = xl_local; - frame->local = local; + if (!local) + goto err; + local->xl_local = xl_local; local->call_count = count; - local->xl_specf_unwind = xl_specf_getxattr_unwind; - local->vol_uuid = vol_uuid; + memcpy (local->gauge, gauge, sizeof (local->gauge)); + + frame->local = local; for (i=0; i < count; i++) { if (MARKER_UUID_TYPE == type) STACK_WIND (frame, cluster_markeruuid_cbk, *(sub_volumes + i), (*(sub_volumes + i))->fops->getxattr, - loc, name); + loc, name, NULL); else if (MARKER_XTIME_TYPE == type) STACK_WIND (frame, cluster_markerxtime_cbk, *(sub_volumes + i), (*(sub_volumes + i))->fops->getxattr, - loc, name); + loc, name, NULL); else { gf_log (this->name, GF_LOG_WARNING, - "Unrecognized type of marker attr received"); + "Unrecognized type (%d) of marker attr " + "received", type); STACK_WIND (frame, default_getxattr_cbk, *(sub_volumes + i), (*(sub_volumes + i))->fops->getxattr, - loc, name); + loc, name, NULL); break; } } @@ -409,3 +413,58 @@ err: return -1; } + +int +gf_get_min_stime (xlator_t *this, dict_t *dst, char *key, data_t *value) +{ + int ret = -1; + uint32_t *net_timebuf = NULL; + uint32_t *value_timebuf = NULL; + uint32_t host_timebuf[2] = {0,}; + uint32_t host_value_timebuf[2] = {0,}; + + /* stime should be minimum of all the other nodes */ + ret = dict_get_bin (dst, key, (void **)&net_timebuf); + if (ret < 0) { + net_timebuf = GF_CALLOC (1, sizeof (int64_t), + gf_common_mt_char); + if (!net_timebuf) + goto out; + + ret = dict_set_bin (dst, key, net_timebuf, sizeof (int64_t)); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "key=%s: dict set failed", key); + goto error; + } + } + + value_timebuf = data_to_bin (value); + if (!value_timebuf) { + gf_log (this->name, GF_LOG_WARNING, + "key=%s: getting value of stime failed", key); + ret = -1; + goto out; + } + + get_hosttime (value_timebuf, host_value_timebuf); + get_hosttime (net_timebuf, host_timebuf); + + /* can't use 'min()' macro here as we need to compare two fields + in the array, selectively */ + if ((host_value_timebuf[0] > host_timebuf[0]) || + ((host_value_timebuf[0] == host_timebuf[0]) && + (host_value_timebuf[1] > host_timebuf[1]))) { + update_timebuf (value_timebuf, net_timebuf); + } + + ret = 0; +out: + return ret; +error: + /* To be used only when net_timebuf is not set in the dict */ + if (net_timebuf) + GF_FREE (net_timebuf); + + return ret; +} |
