diff options
| author | Avra Sengupta <asengupt@redhat.com> | 2016-05-10 12:13:18 +0530 | 
|---|---|---|
| committer | Jeff Darcy <jdarcy@redhat.com> | 2016-05-25 11:52:44 -0700 | 
| commit | f8f16595d8dd8c8a869630bb77b7fd1b42b97e08 (patch) | |
| tree | 8f8d7ff3739a16155331f0411501f94d8849513d /xlators | |
| parent | fb57ac1acb228301edb98f2fe7cf93471363eb4a (diff) | |
jbr: Making fop functions more modular to reuse more code
Putting bigger chunks of re-usable code like leader checks
and init into functions thereby reducing the size of the
'fop' call.
Introduced 'perform_local_op' in the 'fop' call, where
regular functions as of now just call dispatch, but fops
like 'lk' can do their fop specific operations.
Introduced selective_generate to allow certain functions
for a particular fop to be generated. The rest of the
functions can be customised and added in jbr.c
Change-Id: I3754ed68983e763329e14a2faef911428e36e4f0
BUG: 1336328
Signed-off-by: Avra Sengupta <asengupt@redhat.com>
Reviewed-on: http://review.gluster.org/14355
Smoke: Gluster Build System <jenkins@build.gluster.com>
NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
CentOS-regression: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Jeff Darcy <jdarcy@redhat.com>
Diffstat (limited to 'xlators')
| -rw-r--r-- | xlators/experimental/jbr-server/src/all-templates.c | 263 | ||||
| -rwxr-xr-x | xlators/experimental/jbr-server/src/gen-fops.py | 52 | ||||
| -rw-r--r-- | xlators/experimental/jbr-server/src/jbr.c | 122 | 
3 files changed, 313 insertions, 124 deletions
diff --git a/xlators/experimental/jbr-server/src/all-templates.c b/xlators/experimental/jbr-server/src/all-templates.c index 9b9a3e0be5e..adae2431157 100644 --- a/xlators/experimental/jbr-server/src/all-templates.c +++ b/xlators/experimental/jbr-server/src/all-templates.c @@ -9,9 +9,17 @@ int32_t  jbr_@NAME@ (call_frame_t *frame, xlator_t *this,              @LONG_ARGS@)  { -        jbr_private_t   *priv   = this->private; -        gf_boolean_t in_recon = _gf_false; -        int32_t recon_term, recon_index; +        jbr_private_t   *priv     = NULL; +        gf_boolean_t     in_recon = _gf_false; +        int32_t          op_errno = 0; +        int32_t          recon_term, recon_index; + +        GF_VALIDATE_OR_GOTO ("jbr", this, err); +        priv = this->private; +        GF_VALIDATE_OR_GOTO (this->name, priv, err); +        GF_VALIDATE_OR_GOTO (this->name, frame, err); + +        op_errno = EREMOTE;          /* allow reads during reconciliation       *           * TBD: allow "dirty" reads on non-leaders * @@ -32,14 +40,20 @@ jbr_@NAME@ (call_frame_t *frame, xlator_t *this,          return 0;  err: -        STACK_UNWIND_STRICT (@NAME@, frame, -1, EREMOTE, +        STACK_UNWIND_STRICT (@NAME@, frame, -1, op_errno,                               @ERROR_ARGS@);          return 0;  } +/* template-name read-perform_local_op */ +/* No "perform_local_op" function needed for @NAME@ */ +  /* template-name read-dispatch */  /* No "dispatch" function needed for @NAME@ */ +/* template-name read-call_dispatch */ +/* No "call_dispatch" function needed for @NAME@ */ +  /* template-name read-fan-in */  /* No "fan-in" function needed for @NAME@ */ @@ -54,70 +68,25 @@ int32_t  jbr_@NAME@ (call_frame_t *frame, xlator_t *this,              @LONG_ARGS@)  { -        jbr_local_t     *local          = NULL; -        jbr_private_t   *priv           = this->private; -        gf_boolean_t     result         = _gf_false; -        int             op_errno        = ENOMEM; -        int             from_leader; -        int             from_recon; -        uint32_t        ti = 0; - -        /* -         * Our first goal here is to avoid "split brain surprise" for users who -         * specify exactly 50% with two- or three-way replication.  That means -         * either a more-than check against half the total replicas or an -         * at-least check against half of our peers (one less).  Of the two, -         * only an at-least check supports the intuitive use of 100% to mean -         * all replicas must be present, because "more than 100%" will never -         * succeed regardless of which count we use.  This leaves us with a -         * slightly non-traditional definition of quorum ("at least X% of peers -         * not including ourselves") but one that's useful enough to be worth -         * it. -         * -         * Note that n_children and up_children *do* include the local -         * subvolume, so we need to subtract one in each case. -         */ -        if (priv->leader) { -                result = fop_quorum_check (this, (double)(priv->n_children - 1), -                                   (double)(priv->up_children - 1)); - -                if (result == _gf_false) { -                        /* Emulate the AFR client-side-quorum behavior. */ -                        gf_msg (this->name, GF_LOG_ERROR, EROFS, -                                J_MSG_QUORUM_NOT_MET, "Sufficient number of " -                                "subvolumes are not up to meet quorum."); -                        op_errno = EROFS; -                        goto err; -                } -        } else { -                if (xdata) { -                        from_leader = !!dict_get(xdata, JBR_TERM_XATTR); -                        from_recon = !!dict_get(xdata, RECON_TERM_XATTR) -                                  && !!dict_get(xdata, RECON_INDEX_XATTR); -                } else { -                        from_leader = from_recon = _gf_false; -                } +        jbr_local_t     *local         = NULL; +        jbr_private_t   *priv          = NULL; +        int32_t          ret           = -1; +        int              op_errno      = ENOMEM; -                /* follower/recon path        * -                 * just send it to local node * -                 */ -                if (!from_leader && !from_recon) { -                        op_errno = EREMOTE; -                        goto err; -                } -        } +        GF_VALIDATE_OR_GOTO ("jbr", this, err); +        priv = this->private; +        GF_VALIDATE_OR_GOTO (this->name, priv, err); +        GF_VALIDATE_OR_GOTO (this->name, frame, err); -        local = mem_get0(this->local_pool); -        if (!local) { -                goto err; -        }  #if defined(JBR_CG_NEED_FD) -        local->fd = fd_ref(fd); +        ret = jbr_leader_checks_and_init (frame, this, &op_errno, xdata, fd);  #else -        local->fd = NULL; +        ret = jbr_leader_checks_and_init (frame, this, &op_errno, xdata, NULL);  #endif -        INIT_LIST_HEAD(&local->qlinks); -        frame->local = local; +        if (ret) +                goto err; + +        local = frame->local;          /*           * If we let it through despite not being the leader, then we just want @@ -132,29 +101,9 @@ jbr_@NAME@ (call_frame_t *frame, xlator_t *this,                  return 0;          } -        if (!xdata) { -                xdata = dict_new(); -                if (!xdata) { -                        gf_msg (this->name, GF_LOG_ERROR, ENOMEM, -                                J_MSG_MEM_ERR, "failed to allocate xdata"); -                        goto err; -                } -        } - -        if (dict_set_int32(xdata, JBR_TERM_XATTR, priv->current_term) != 0) { -                gf_msg (this->name, GF_LOG_ERROR, 0, -                        J_MSG_DICT_FLR, "failed to set jbr-term"); +        ret = jbr_initialize_xdata_set_attrs (this, &xdata); +        if (ret)                  goto err; -        } - -        LOCK(&priv->index_lock); -        ti = ++(priv->index); -        UNLOCK(&priv->index_lock); -        if (dict_set_int32(xdata, JBR_INDEX_XATTR, ti) != 0) { -                gf_msg (this->name, GF_LOG_ERROR, 0, -                        J_MSG_DICT_FLR, "failed to set index"); -                goto err; -        }          local->stub = fop_@NAME@_stub (frame, jbr_@NAME@_continue,                                         @SHORT_ARGS@); @@ -162,14 +111,77 @@ jbr_@NAME@ (call_frame_t *frame, xlator_t *this,                  goto err;          } +        /* +         * Can be used to just call_dispatch or be customised per fop to * +         * perform ops specific to that particular fop.                  * +         */ +        ret = jbr_@NAME@_perform_local_op (frame, this, &op_errno, +                                           @SHORT_ARGS@); +        if (ret) +                goto err; -#if defined(JBR_CG_QUEUE) -        jbr_inode_ctx_t         *ictx   = jbr_get_inode_ctx(this, fd->inode); +        return ret; +err: +        if (local) { +                if (local->stub) { +                        call_stub_destroy(local->stub); +                } +                if (local->qstub) { +                        call_stub_destroy(local->qstub); +                } +                if (local->fd) { +                        fd_unref(local->fd); +                } +                mem_put(local); +        } +        STACK_UNWIND_STRICT (@NAME@, frame, -1, op_errno, +                             @ERROR_ARGS@); +        return 0; +} + +/* template-name write-perform_local_op */ +int32_t +jbr_@NAME@_perform_local_op (call_frame_t *frame, xlator_t *this, int *op_errno, +                             @LONG_ARGS@) +{ +        int32_t          ret    = -1; + +        GF_VALIDATE_OR_GOTO ("jbr", this, out); +        GF_VALIDATE_OR_GOTO (this->name, frame, out); +        GF_VALIDATE_OR_GOTO (this->name, op_errno, out); +        ret = jbr_@NAME@_call_dispatch (frame, this, op_errno, +                                        @SHORT_ARGS@); + +out: +        return ret; +} + +/* template-name write-call_dispatch */ +int32_t +jbr_@NAME@_call_dispatch (call_frame_t *frame, xlator_t *this, int *op_errno, +                          @LONG_ARGS@) +{ +        jbr_local_t     *local  = NULL; +        jbr_private_t   *priv   = NULL; +        int32_t          ret    = -1; +        xlator_list_t   *trav   = NULL; + +        GF_VALIDATE_OR_GOTO ("jbr", this, out); +        priv = this->private; +        GF_VALIDATE_OR_GOTO (this->name, priv, out); +        GF_VALIDATE_OR_GOTO (this->name, frame, out); +        local = frame->local; +        GF_VALIDATE_OR_GOTO (this->name, local, out); +        GF_VALIDATE_OR_GOTO (this->name, op_errno, out); + +#if defined(JBR_CG_QUEUE) +        jbr_inode_ctx_t  *ictx  = jbr_get_inode_ctx(this, fd->inode);          if (!ictx) { -                op_errno = EIO; -                goto err; +                *op_errno = EIO; +                goto out;          } +          LOCK(&ictx->lock);                  if (ictx->active) {                          gf_msg_debug (this->name, 0, @@ -194,37 +206,23 @@ jbr_@NAME@ (call_frame_t *frame, xlator_t *this,                                                          @SHORT_ARGS@);                          if (!local->qstub) {                                  UNLOCK(&ictx->lock); -                                goto err; +                                goto out;                          }                          list_add_tail(&local->qlinks, &ictx->pqueue);                          ++(ictx->pending);                          UNLOCK(&ictx->lock); -                        return 0; +                        ret = 0; +                        goto out;                  } else {                          list_add_tail(&local->qlinks, &ictx->aqueue);                          ++(ictx->active);                  }          UNLOCK(&ictx->lock);  #endif +        ret = jbr_@NAME@_dispatch (frame, this, @SHORT_ARGS@); -        return jbr_@NAME@_dispatch (frame, this, @SHORT_ARGS@); - -err: -        if (local) { -                if (local->stub) { -                        call_stub_destroy(local->stub); -                } -                if (local->qstub) { -                        call_stub_destroy(local->qstub); -                } -                if (local->fd) { -                        fd_unref(local->fd); -                } -                mem_put(local); -        } -        STACK_UNWIND_STRICT (@NAME@, frame, -1, op_errno, -                             @ERROR_ARGS@); -        return 0; +out: +        return ret;  }  /* template-name write-dispatch */ @@ -232,10 +230,18 @@ int32_t  jbr_@NAME@_dispatch (call_frame_t *frame, xlator_t *this,                       @LONG_ARGS@)  { -        jbr_local_t     *local  = frame->local; -        jbr_private_t   *priv   = this->private; +        jbr_local_t     *local  = NULL; +        jbr_private_t   *priv   = NULL; +        int32_t          ret    = -1;          xlator_list_t   *trav; +        GF_VALIDATE_OR_GOTO ("jbr", this, out); +        priv = this->private; +        GF_VALIDATE_OR_GOTO (this->name, priv, out); +        GF_VALIDATE_OR_GOTO (this->name, frame, out); +        local = frame->local; +        GF_VALIDATE_OR_GOTO (this->name, local, out); +          /*           * TBD: unblock pending request(s) if we fail after this point but           * before we get to jbr_@NAME@_complete (where that code currently @@ -251,7 +257,9 @@ jbr_@NAME@_dispatch (call_frame_t *frame, xlator_t *this,          }          /* TBD: variable Issue count */ -        return 0; +        ret = 0; +out: +        return ret;  }  /* template-name write-fan-in */ @@ -260,8 +268,14 @@ jbr_@NAME@_fan_in (call_frame_t *frame, void *cookie, xlator_t *this,                     int32_t op_ret, int32_t op_errno,                     @LONG_ARGS@)  { -        jbr_local_t     *local  = frame->local; -        uint8_t         call_count; +        jbr_local_t   *local  = NULL; +        int32_t        ret    = -1; +        uint8_t        call_count; + +        GF_VALIDATE_OR_GOTO ("jbr", this, out); +        GF_VALIDATE_OR_GOTO (this->name, frame, out); +        local = frame->local; +        GF_VALIDATE_OR_GOTO (this->name, local, out);          gf_msg_trace (this->name, 0, "op_ret = %d, op_errno = %d\n",                        op_ret, op_errno); @@ -284,7 +298,9 @@ jbr_@NAME@_fan_in (call_frame_t *frame, void *cookie, xlator_t *this,                  call_resume(local->stub);          } -        return 0; +        ret = 0; +out: +        return ret;  }  /* template-name write-continue */ @@ -335,10 +351,16 @@ jbr_@NAME@_complete (call_frame_t *frame, void *cookie, xlator_t *this,                       int32_t op_ret, int32_t op_errno,                       @LONG_ARGS@)  { -        gf_boolean_t     result         = _gf_false; -        jbr_private_t   *priv           = this->private; +        gf_boolean_t     result    = _gf_false; +        jbr_private_t   *priv      = NULL; +        jbr_local_t     *local     = NULL; -        jbr_local_t *local = frame->local; +        GF_VALIDATE_OR_GOTO ("jbr", this, err); +        GF_VALIDATE_OR_GOTO (this->name, frame, err); +        priv = this->private; +        local = frame->local; +        GF_VALIDATE_OR_GOTO (this->name, priv, err); +        GF_VALIDATE_OR_GOTO (this->name, local, err);          /* If the fop failed on the leader, then reduce one succesful ack           * before calculating the fop quorum @@ -434,4 +456,9 @@ jbr_@NAME@_complete (call_frame_t *frame, void *cookie, xlator_t *this,          return 0; +err: +        STACK_UNWIND_STRICT (@NAME@, frame, -1, 0, +                             @SHORT_ARGS@); + +        return 0;  } diff --git a/xlators/experimental/jbr-server/src/gen-fops.py b/xlators/experimental/jbr-server/src/gen-fops.py index 64cbe4f760e..36bf1e35d27 100755 --- a/xlators/experimental/jbr-server/src/gen-fops.py +++ b/xlators/experimental/jbr-server/src/gen-fops.py @@ -78,7 +78,7 @@ fop_table = {  	"getxattr":		"read",  #	"inodelk":		"read",  	"link":			"write", -#	"lk":			"read", +#	"lk":			"write",  #	"lookup":		"read",  	"mkdir":		"write",  	"mknod":		"write", @@ -103,6 +103,13 @@ fop_table = {  	"xattrop":		"write",  } +# Mention those fops in the selective_generate table, for which +# only a few common functions will be generated, and mention those +# functions. Rest of the functions can be customized +selective_generate = { +#	"lk":			"fop,dispatch,call_dispatch", +} +  # Stolen from gen_fdl.py  def gen_server (templates):  	fops_done = [] @@ -110,15 +117,48 @@ def gen_server (templates):  		info = fop_table[name].split(",")  		kind = info[0]  		flags = info[1:] + +		# generate all functions for the fops in fop_table +		# except for the ones in selective_generate for which +		# generate only the functions mentioned in the +		# selective_generate table +		gen_funcs = "fop,complete,continue,fan-in,dispatch, \ +			call_dispatch,perform_local_op" +		if name in selective_generate: +			gen_funcs = selective_generate[name].split(",") +  		if ("fsync" in flags) or ("queue" in flags):  			flags.append("need_fd")  		for fname in flags:  			print "#define JBR_CG_%s" % fname.upper() -		print generate(templates[kind+"-complete"],name,cbk_subs) -		print generate(templates[kind+"-continue"],name,fop_subs) -		print generate(templates[kind+"-fan-in"],name,cbk_subs) -		print generate(templates[kind+"-dispatch"],name,fop_subs) -		print generate(templates[kind+"-fop"],name,fop_subs) + +		if 'complete' in gen_funcs: +			print generate(templates[kind+"-complete"], +					name,cbk_subs) + +		if 'continue' in gen_funcs: +			print generate(templates[kind+"-continue"], +					name,fop_subs) + +		if 'fan-in' in gen_funcs: +			print generate(templates[kind+"-fan-in"], +					name,cbk_subs) + +		if 'dispatch' in gen_funcs: +			print generate(templates[kind+"-dispatch"], +					name,fop_subs) + +		if 'call_dispatch' in gen_funcs: +			print generate(templates[kind+"-call_dispatch"], +					name,fop_subs) + +		if 'perform_local_op' in gen_funcs: +			print generate(templates[kind+"-perform_local_op"], +					name, fop_subs) + +		if 'fop' in gen_funcs: +			print generate(templates[kind+"-fop"],name,fop_subs) +  		for fname in flags:  			print "#undef JBR_CG_%s" % fname.upper()  		fops_done.append(name) diff --git a/xlators/experimental/jbr-server/src/jbr.c b/xlators/experimental/jbr-server/src/jbr.c index 984392c2f87..a342d3b83d5 100644 --- a/xlators/experimental/jbr-server/src/jbr.c +++ b/xlators/experimental/jbr-server/src/jbr.c @@ -190,6 +190,128 @@ jbr_mark_fd_dirty (xlator_t *this, jbr_local_t *local)  #define RECON_TERM_XATTR        "trusted.jbr.recon-term"  #define RECON_INDEX_XATTR       "trusted.jbr.recon-index" +int32_t +jbr_leader_checks_and_init (call_frame_t *frame, xlator_t *this, int *op_errno, +                            dict_t *xdata, fd_t *fd) +{ +        jbr_local_t     *local         = NULL; +        jbr_private_t   *priv          = NULL; +        int32_t          ret           = -1; +        gf_boolean_t     result        = _gf_false; +        int              from_leader   = _gf_false; +        int              from_recon    = _gf_false; + +        GF_VALIDATE_OR_GOTO ("jbr", this, out); +        priv = this->private; +        GF_VALIDATE_OR_GOTO (this->name, priv, out); +        GF_VALIDATE_OR_GOTO (this->name, op_errno, out); +        GF_VALIDATE_OR_GOTO (this->name, frame, out); + +        /* +         * Our first goal here is to avoid "split brain surprise" for users who +         * specify exactly 50% with two- or three-way replication.  That means +         * either a more-than check against half the total replicas or an +         * at-least check against half of our peers (one less).  Of the two, +         * only an at-least check supports the intuitive use of 100% to mean +         * all replicas must be present, because "more than 100%" will never +         * succeed regardless of which count we use.  This leaves us with a +         * slightly non-traditional definition of quorum ("at least X% of peers +         * not including ourselves") but one that's useful enough to be worth +         * it. +         * +         * Note that n_children and up_children *do* include the local +         * subvolume, so we need to subtract one in each case. +         */ +        if (priv->leader) { +                result = fop_quorum_check (this, (double)(priv->n_children - 1), +                                   (double)(priv->up_children - 1)); + +                if (result == _gf_false) { +                        /* Emulate the AFR client-side-quorum behavior. */ +                        gf_msg (this->name, GF_LOG_ERROR, EROFS, +                                J_MSG_QUORUM_NOT_MET, "Sufficient number of " +                                "subvolumes are not up to meet quorum."); +                        *op_errno = EROFS; +                        goto out; +                } +        } else { +                if (xdata) { +                        from_leader = !!dict_get(xdata, JBR_TERM_XATTR); +                        from_recon = !!dict_get(xdata, RECON_TERM_XATTR) +                                  && !!dict_get(xdata, RECON_INDEX_XATTR); +                } else { +                        from_leader = from_recon = _gf_false; +                } + +                /* follower/recon path        * +                 * just send it to local node * +                 */ +                if (!from_leader && !from_recon) { +                        *op_errno = EREMOTE; +                        goto out; +                } +        } + +        local = mem_get0(this->local_pool); +        if (!local) { +                goto out; +        } + +        if (fd) +                local->fd = fd_ref(fd); +        else +                local->fd = NULL; + +        INIT_LIST_HEAD(&local->qlinks); +        frame->local = local; + +        ret = 0; +out: +        return ret; +} + +int32_t +jbr_initialize_xdata_set_attrs (xlator_t *this, dict_t **xdata) +{ +        jbr_local_t     *local         = NULL; +        jbr_private_t   *priv          = NULL; +        int32_t          ret           = -1; +        uint32_t         ti            = 0; + +        GF_VALIDATE_OR_GOTO ("jbr", this, out); +        priv = this->private; +        GF_VALIDATE_OR_GOTO (this->name, priv, out); +        GF_VALIDATE_OR_GOTO (this->name, xdata, out); + +        if (!*xdata) { +                *xdata = dict_new(); +                if (!*xdata) { +                        gf_msg (this->name, GF_LOG_ERROR, ENOMEM, +                                J_MSG_MEM_ERR, "failed to allocate xdata"); +                        goto out; +                } +        } + +        if (dict_set_int32(*xdata, JBR_TERM_XATTR, priv->current_term) != 0) { +                gf_msg (this->name, GF_LOG_ERROR, 0, +                        J_MSG_DICT_FLR, "failed to set jbr-term"); +                goto out; +        } + +        LOCK(&priv->index_lock); +        ti = ++(priv->index); +        UNLOCK(&priv->index_lock); +        if (dict_set_int32(*xdata, JBR_INDEX_XATTR, ti) != 0) { +                gf_msg (this->name, GF_LOG_ERROR, 0, +                        J_MSG_DICT_FLR, "failed to set index"); +                goto out; +        } + +        ret = 0; +out: +        return ret; +} +  #pragma generate  uint8_t  | 
