/* * Allocates and sends transaction into given @st network state/connection. * Uses @s session only to get wait timeout for transaction, if it is NULL, global node timeout (@dnet_node::wait_ts) is used. * * If something fails, completion handler from @ctl will be invoked with (NULL, NULL, @ctl->priv) arguments */ int dnet_trans_alloc_send_state(struct dnet_session *s, struct dnet_net_state *st, struct dnet_trans_control *ctl) { struct dnet_io_req req; struct dnet_node *n = st->n; struct dnet_cmd *cmd; struct dnet_trans *t; int err; t = dnet_trans_alloc(n, sizeof(struct dnet_cmd) + ctl->size); if (!t) { err = dnet_trans_send_fail(s, dnet_state_addr(st), ctl, -ENOMEM, 1); goto err_out_exit; } t->complete = ctl->complete; t->priv = ctl->priv; if (s) { t->wait_ts = *dnet_session_get_timeout(s); } cmd = (struct dnet_cmd *)(t + 1); dnet_trans_control_fill_cmd(s, ctl, cmd); t->command = cmd->cmd; cmd->trans = t->rcv_trans = t->trans = atomic_inc(&n->trans); memcpy(&t->cmd, cmd, sizeof(struct dnet_cmd)); if (ctl->size && ctl->data) memcpy(cmd + 1, ctl->data, ctl->size); dnet_convert_cmd(cmd); t->st = dnet_state_get(st); memset(&req, 0, sizeof(req)); req.st = st; req.header = cmd; req.hsize = sizeof(struct dnet_cmd) + ctl->size; req.fd = -1; dnet_log(n, DNET_LOG_INFO, "%s: %s: created %s", dnet_dump_id(&cmd->id), dnet_cmd_string(cmd->cmd), dnet_print_trans(t) ); err = dnet_trans_send(t, &req); if (err) goto err_out_put; return 0; err_out_put: dnet_trans_send_fail(s, dnet_state_addr(st), ctl, err, 0); dnet_trans_put(t); err_out_exit: return 0; }
void dnet_trans_clean_list(struct list_head *head, int error) { struct dnet_trans *t, *tmp; list_for_each_entry_safe(t, tmp, head, trans_list_entry) { list_del_init(&t->trans_list_entry); t->cmd.size = 0; t->cmd.flags &= ~DNET_FLAGS_REPLY; t->cmd.status = error; dnet_node_set_trace_id(t->cmd.trace_id, t->cmd.flags & DNET_FLAGS_TRACE_BIT); if (t->complete) { t->complete(dnet_state_addr(t->st), &t->cmd, t->priv); } dnet_trans_put(t); dnet_node_unset_trace_id(); }
static int dnet_send_idc(struct dnet_net_state *lstate, struct dnet_net_state *send, struct dnet_id *id, uint64_t trans, unsigned int command, int reply, int direct, int more) { struct dnet_node *n = lstate->n; int size = sizeof(struct dnet_addr_cmd) + sizeof(struct dnet_addr) * n->addr_num + lstate->idc->id_num * sizeof(struct dnet_raw_id); void *buf; int err; struct dnet_addr laddr; char server_addr[128], client_addr[128]; struct timeval start, end; long diff; gettimeofday(&start, NULL); buf = malloc(size); if (!buf) { err = -ENOMEM; goto err_out_exit; } memset(buf, 0, size); dnet_send_idc_fill(lstate, buf, size, id, trans, command, reply, direct, more); dnet_socket_local_addr(send->read_s, &laddr); gettimeofday(&end, NULL); diff = (end.tv_sec - start.tv_sec) * 1000000 + end.tv_usec - start.tv_usec; dnet_log(n, DNET_LOG_INFO, "%s: sending address %s -> %s, addr_num: %d, time-took: %ld\n", dnet_dump_id(id), dnet_server_convert_dnet_addr_raw(&laddr, server_addr, sizeof(server_addr)), dnet_server_convert_dnet_addr_raw(dnet_state_addr(send), client_addr, sizeof(client_addr)), n->addr_num, diff); err = dnet_send(send, buf, size); free(buf); err_out_exit: return err; }
void dnet_trans_destroy(struct dnet_trans *t) { struct dnet_net_state *st = NULL; struct timeval tv; long diff; if (!t) return; dnet_node_set_trace_id(t->cmd.trace_id, t->cmd.flags & DNET_FLAGS_TRACE_BIT); gettimeofday(&tv, NULL); diff = 1000000 * (tv.tv_sec - t->start.tv_sec) + (tv.tv_usec - t->start.tv_usec); if (t->st && t->st->n) { st = t->st; pthread_mutex_lock(&st->trans_lock); list_del_init(&t->trans_list_entry); if (t->trans_entry.rb_parent_color) { dnet_trans_remove_nolock(st, t); } pthread_mutex_unlock(&st->trans_lock); } else if (!list_empty(&t->trans_list_entry)) { assert(0); } if (t->complete) { t->cmd.flags |= DNET_FLAGS_DESTROY; t->complete(t->st ? dnet_state_addr(t->st) : NULL, &t->cmd, t->priv); } if (st && st->n && t->command != 0) { char str[64]; char io_buf[1024] = ""; struct tm tm; if (t->cmd.status != -ETIMEDOUT) { if (st->stall) { dnet_log(st->n, DNET_LOG_INFO, "%s/%d: reseting state stall counter", dnet_state_dump_addr(st), t->cmd.backend_id); } st->stall = 0; } localtime_r((time_t *)&t->start.tv_sec, &tm); strftime(str, sizeof(str), "%F %R:%S", &tm); if ((t->command == DNET_CMD_READ || t->command == DNET_CMD_WRITE) && (t->alloc_size >= sizeof(struct dnet_cmd) + sizeof(struct dnet_io_attr))) { struct dnet_cmd *local_cmd = (struct dnet_cmd *)(t + 1); struct dnet_io_attr *local_io = (struct dnet_io_attr *)(local_cmd + 1); double backend_weight = 0.; dnet_get_backend_weight(st, t->cmd.backend_id, local_io->flags, &backend_weight); snprintf(io_buf, sizeof(io_buf), ", weight: %f, %s", backend_weight, dnet_print_io(local_io)); } dnet_log(st->n, DNET_LOG_INFO, "%s: %s: destruction %s, stall: %d, " "time: %ld, started: %s.%06lu, cached status: %d%s", dnet_dump_id(&t->cmd.id), dnet_cmd_string(t->cmd.cmd), dnet_print_trans(t), t->st->stall, diff, str, t->start.tv_usec, t->cmd.status, io_buf); } dnet_state_put(t->st); dnet_state_put(t->orig); dnet_node_unset_trace_id(); free(t); }