diff options
Diffstat (limited to 'xlators/cluster/ec/src/ec-data.c')
| -rw-r--r-- | xlators/cluster/ec/src/ec-data.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/xlators/cluster/ec/src/ec-data.c b/xlators/cluster/ec/src/ec-data.c new file mode 100644 index 00000000000..06388833546 --- /dev/null +++ b/xlators/cluster/ec/src/ec-data.c @@ -0,0 +1,288 @@ +/* + Copyright (c) 2012-2014 DataLab, s.l. <http://www.datalab.es> + 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 "ec-helpers.h" +#include "ec-common.h" +#include "ec-data.h" +#include "ec-messages.h" + +ec_cbk_data_t * +ec_cbk_data_allocate(call_frame_t *frame, xlator_t *this, ec_fop_data_t *fop, + int32_t id, int32_t idx, int32_t op_ret, int32_t op_errno) +{ + ec_cbk_data_t *cbk; + ec_t *ec = this->private; + + if (fop->xl != this) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, EC_MSG_XLATOR_MISMATCH, + "Mismatching xlators between request " + "and answer (req=%s, ans=%s).", + fop->xl->name, this->name); + + return NULL; + } + if (fop->frame != frame) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, EC_MSG_FRAME_MISMATCH, + "Mismatching frames between request " + "and answer (req=%p, ans=%p).", + fop->frame, frame); + + return NULL; + } + if (fop->id != id) { + gf_msg(this->name, GF_LOG_ERROR, EINVAL, EC_MSG_FOP_MISMATCH, + "Mismatching fops between request " + "and answer (req=%d, ans=%d).", + fop->id, id); + + return NULL; + } + + cbk = mem_get0(ec->cbk_pool); + if (cbk == NULL) { + gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY, + "Failed to allocate memory for an " + "answer."); + return NULL; + } + + cbk->fop = fop; + cbk->idx = idx; + cbk->mask = 1ULL << idx; + cbk->count = 1; + cbk->op_ret = op_ret; + cbk->op_errno = op_errno; + INIT_LIST_HEAD(&cbk->entries.list); + + LOCK(&fop->lock); + + list_add_tail(&cbk->answer_list, &fop->answer_list); + + UNLOCK(&fop->lock); + + return cbk; +} + +void +ec_cbk_data_destroy(ec_cbk_data_t *cbk) +{ + if (cbk->xdata != NULL) { + dict_unref(cbk->xdata); + } + if (cbk->dict != NULL) { + dict_unref(cbk->dict); + } + if (cbk->inode != NULL) { + inode_unref(cbk->inode); + } + if (cbk->fd != NULL) { + fd_unref(cbk->fd); + } + if (cbk->buffers != NULL) { + iobref_unref(cbk->buffers); + } + GF_FREE(cbk->vector); + gf_dirent_free(&cbk->entries); + GF_FREE(cbk->str); + + mem_put(cbk); +} + +ec_fop_data_t * +ec_fop_data_allocate(call_frame_t *frame, xlator_t *this, int32_t id, + uint32_t flags, uintptr_t target, uint32_t fop_flags, + ec_wind_f wind, ec_handler_f handler, ec_cbk_t cbks, + void *data) +{ + ec_fop_data_t *fop, *parent; + ec_t *ec = this->private; + + fop = mem_get0(ec->fop_pool); + if (fop == NULL) { + gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY, + "Failed to allocate memory for a " + "request."); + + return NULL; + } + + INIT_LIST_HEAD(&fop->cbk_list); + INIT_LIST_HEAD(&fop->healer); + INIT_LIST_HEAD(&fop->answer_list); + INIT_LIST_HEAD(&fop->pending_list); + INIT_LIST_HEAD(&fop->locks[0].owner_list); + INIT_LIST_HEAD(&fop->locks[0].wait_list); + INIT_LIST_HEAD(&fop->locks[1].owner_list); + INIT_LIST_HEAD(&fop->locks[1].wait_list); + + fop->xl = this; + fop->req_frame = frame; + + /* fops need a private frame to be able to execute some postop operations + * even if the original fop has completed and reported back to the upper + * xlator and it has destroyed the base frame. + * + * TODO: minimize usage of private frames. Reuse req_frame as much as + * possible. + */ + if (frame != NULL) { + fop->frame = copy_frame(frame); + } else { + fop->frame = create_frame(this, this->ctx->pool); + } + if (fop->frame == NULL) { + gf_msg(this->name, GF_LOG_ERROR, ENOMEM, EC_MSG_NO_MEMORY, + "Failed to create a private frame " + "for a request"); + + mem_put(fop); + + return NULL; + } + fop->id = id; + fop->refs = 1; + + fop->flags = flags; + fop->minimum = EC_FOP_MINIMUM(fop_flags); + fop->fop_flags = EC_FOP_FLAGS(fop_flags); + fop->mask = target; + + fop->wind = wind; + fop->handler = handler; + fop->cbks = cbks; + fop->data = data; + + fop->uid = fop->frame->root->uid; + fop->gid = fop->frame->root->gid; + + LOCK_INIT(&fop->lock); + + fop->frame->local = fop; + + if (frame != NULL) { + parent = frame->local; + if (parent != NULL) { + ec_sleep(parent); + } + + fop->parent = parent; + } + + LOCK(&ec->lock); + + list_add_tail(&fop->pending_list, &ec->pending_fops); + + UNLOCK(&ec->lock); + + return fop; +} + +void +ec_fop_data_acquire(ec_fop_data_t *fop) +{ + LOCK(&fop->lock); + + ec_trace("ACQUIRE", fop, ""); + + fop->refs++; + + UNLOCK(&fop->lock); +} + +static void +ec_handle_last_pending_fop_completion(ec_fop_data_t *fop, gf_boolean_t *notify) +{ + ec_t *ec = fop->xl->private; + + *notify = _gf_false; + + if (!list_empty(&fop->pending_list)) { + LOCK(&ec->lock); + { + list_del_init(&fop->pending_list); + *notify = __ec_is_last_fop(ec); + } + UNLOCK(&ec->lock); + } +} + +void +ec_fop_cleanup(ec_fop_data_t *fop) +{ + ec_cbk_data_t *cbk, *tmp; + + list_for_each_entry_safe(cbk, tmp, &fop->answer_list, answer_list) + { + list_del_init(&cbk->answer_list); + + ec_cbk_data_destroy(cbk); + } + INIT_LIST_HEAD(&fop->cbk_list); + + fop->answer = NULL; +} + +void +ec_fop_data_release(ec_fop_data_t *fop) +{ + ec_t *ec = NULL; + int32_t refs; + gf_boolean_t notify = _gf_false; + + LOCK(&fop->lock); + + ec_trace("RELEASE", fop, ""); + + GF_ASSERT(fop->refs > 0); + refs = --fop->refs; + + UNLOCK(&fop->lock); + + if (refs == 0) { + fop->frame->local = NULL; + STACK_DESTROY(fop->frame->root); + + LOCK_DESTROY(&fop->lock); + + if (fop->xdata != NULL) { + dict_unref(fop->xdata); + } + if (fop->dict != NULL) { + dict_unref(fop->dict); + } + if (fop->inode != NULL) { + inode_unref(fop->inode); + } + if (fop->fd != NULL) { + fd_unref(fop->fd); + } + if (fop->buffers != NULL) { + iobref_unref(fop->buffers); + } + GF_FREE(fop->vector); + GF_FREE(fop->str[0]); + GF_FREE(fop->str[1]); + loc_wipe(&fop->loc[0]); + loc_wipe(&fop->loc[1]); + GF_FREE(fop->errstr); + + ec_resume_parent(fop); + + ec_fop_cleanup(fop); + + ec = fop->xl->private; + ec_handle_last_pending_fop_completion(fop, ¬ify); + ec_handle_healers_done(fop); + mem_put(fop); + if (notify) { + ec_pending_fops_completed(ec); + } + } +} |
