static int dnet_node_check_stack(struct dnet_node *n) { size_t stack_size; size_t min_stack_size = 1024 * 1024; int err; err = pthread_attr_getstacksize(&n->attr, &stack_size); if (err) { err = -err; dnet_log_err(n, "Failed to get stack size: %d", err); goto err_out_exit; } if (stack_size < min_stack_size) { dnet_log(n, DNET_LOG_ERROR, "Stack size (%zd bytes) is too small, should be at least %zd, exiting", stack_size, min_stack_size); err = -ENOMEM; goto err_out_exit; } dnet_log(n, DNET_LOG_NOTICE, "Stack size: %zd bytes", stack_size); err_out_exit: return err; }
static int dnet_merge_direct(struct dnet_session *s, struct dnet_meta_container *mc) { struct dnet_node *n = s->node; struct dnet_net_state *base; int cflags = 0; int err; dnet_log(n, DNET_LOG_DEBUG, "in dnet_merge_direct mc->size = %u\n", mc->size); base = dnet_node_state(n); if (!base) { err = -ENOENT; goto err_out_exit; } err = n->cb->send(base, n->cb->command_private, &mc->id); dnet_log(n, DNET_LOG_DEBUG, "in dnet_merge_direct after n->cb->send err = %d\n\n", err); if (err < 0) goto err_out_put; dnet_log(n, DNET_LOG_DEBUG, "in dnet_merge_direct2 mc->size = %u\n", mc->size); err = dnet_write_metadata(s, mc, 0, cflags); if (err <= 0) goto err_out_put; err = 0; err_out_put: dnet_state_put(base); err_out_exit: return err; }
static int dnet_merge_common(struct dnet_session *s, struct dnet_meta_container *remote_meta, struct dnet_meta_container *mc) { struct dnet_node *n = s->node; int err = 0; struct dnet_meta_update local, remote; uint64_t cflags = 0; uint64_t ioflags = 0; dnet_log(n, DNET_LOG_DEBUG, "in dnet_merge_common mc->size = %d\n", mc->size); if (!dnet_get_meta_update(n, mc, &local)) { err = -ENOENT; dnet_log(n, DNET_LOG_ERROR, "%s: META_UPDATE not found in local meta\n", dnet_dump_id(&mc->id)); goto err_out_exit; } if (!dnet_get_meta_update(n, remote_meta, &remote)) { err = -ENOENT; dnet_log(n, DNET_LOG_ERROR, "%s: META_UPDATE not found in remote meta, perform direct merge\n", dnet_dump_id(&mc->id)); err = dnet_merge_direct(s, mc); goto err_out_exit; } if ((local.tm.tsec > remote.tm.tsec) || (local.tm.tsec == remote.tm.tsec && local.tm.tnsec > remote.tm.tnsec)) { if (local.flags & DNET_IO_FLAGS_REMOVED) { err = dnet_remove_object_now(s, &mc->id, cflags, ioflags); } else { err = dnet_merge_direct(s, mc); } } err_out_exit: return err; }
static int dnet_bulk_check_complete(struct dnet_net_state *state, struct dnet_cmd *cmd, void *priv) { struct dnet_bulk_check_priv *p = priv; int err = 0, i; if (is_trans_destroyed(state, cmd)) { dnet_wakeup(p->w, p->w->cond++); dnet_wait_put(p->w); dnet_check_temp_db_put(p->db); if (atomic_dec_and_test(&p->refcnt)) { free(p->groups); free(p); } return 0; } /* Empty reply that prevents timeout */ if (cmd->size == 0) { return 0; } if (!(cmd->size % sizeof(struct dnet_bulk_id))) { struct dnet_bulk_id *ids = (struct dnet_bulk_id *)(cmd + 1); int num = cmd->size / sizeof(struct dnet_bulk_id); dnet_log(state->n, DNET_LOG_DEBUG, "BULK: received %d entries\n", num); //dnet_db_ptr_get(&state->n->temp_meta); //ret = kcdbbegintran(state->n->temp_meta.db, 0); //if (!ret) { // err = -kcdbecode(state->n->temp_meta.db); // dnet_log_raw(state->n, DNET_LOG_ERROR, "BULK: DB: failed to start temp_meta transaction, err: %d: %s.\n", // err, kcecodename(-err)); // return err; //} for (i = 0; i < num && !state->n->need_exit; ++i) { err = dnet_bulk_check_complete_single(state, &ids[i], cmd->id.group_id, p); } //kcdbendtran(state->n->temp_meta.db, 1); //dnet_db_ptr_put(state->n, &state->n->temp_meta); if (err) { dnet_log(state->n, DNET_LOG_ERROR, "BULK: couldn't update meta CHECK_STATUS\n"); } } else { dnet_log(state->n, DNET_LOG_ERROR, "BULK: received corrupted data, size = %llu, sizeof(dnet_bulk_id) = %zu\n", (unsigned long long)cmd->size, sizeof(struct dnet_bulk_id)); } p->w->status = cmd->status; return err; }
void server::listen() { while (!m_monitor.node()->need_exit) { try { async_accept(); m_io_service.run(); } catch (const std::exception &e) { dnet_log(m_monitor.node(), DNET_LOG_ERROR, "monitor: server: got exception: %s, restarting it", e.what()); } catch (...) { dnet_log(m_monitor.node(), DNET_LOG_ERROR, "monitor: server: got unknown exception, restarting"); } } }
int dnet_trans_insert_nolock(struct dnet_net_state *st, struct dnet_trans *a) { struct rb_root *root = &st->trans_root; struct rb_node **n = &root->rb_node, *parent = NULL; struct dnet_trans *t; int cmp; while (*n) { parent = *n; t = rb_entry(parent, struct dnet_trans, trans_entry); cmp = dnet_trans_cmp(t->trans, a->trans); if (cmp < 0) n = &parent->rb_left; else if (cmp > 0) n = &parent->rb_right; else return -EEXIST; } if (a->st && a->st->n) dnet_log(a->st->n, DNET_LOG_NOTICE, "%s: %s: added trans: %llu -> %s/%d", dnet_dump_id(&a->cmd.id), dnet_cmd_string(a->cmd.cmd), (unsigned long long)a->trans, dnet_addr_string(&a->st->addr), a->cmd.backend_id); rb_link_node(&a->trans_entry, parent, n); rb_insert_color(&a->trans_entry, root); return 0; }
static int dnet_send_idc(struct dnet_net_state *orig, 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 = orig->n; int size = sizeof(struct dnet_addr_cmd) + orig->idc->id_num * sizeof(struct dnet_raw_id); void *buf; int err; struct timeval start, end; long diff; gettimeofday(&start, NULL); buf = malloc(size); if (!buf) { err = -ENOMEM; goto err_out_exit; } memset(buf, 0, sizeof(struct dnet_addr_cmd)); dnet_send_idc_fill(orig, buf, size, id, trans, command, reply, direct, more); 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: %ld\n", dnet_dump_id(id), dnet_state_dump_addr(orig), diff); err = dnet_send(send, buf, size); free(buf); err_out_exit: return err; }
void dnet_server_node_destroy(struct dnet_node *n) { dnet_log(n, DNET_LOG_DEBUG, "Destroying server node.\n"); /* * Cache can be accessed from the io threads, so firstly stop them. * Cache uses backend to dump all ansynced data to the disk, so * backend must be destroyed the last. * * After all of them finish destroying the node, all it's counters and so on. */ dnet_node_cleanup_common_resources(n); dnet_srw_cleanup(n); dnet_cache_cleanup(n); if (n->cache_pages_proportions) free(n->cache_pages_proportions); if (n->cb && n->cb->backend_cleanup) n->cb->backend_cleanup(n->cb->command_private); dnet_counter_destroy(n); dnet_locks_destroy(n); dnet_local_addr_cleanup(n); dnet_notify_exit(n); if (n->config_data) n->config_data->destroy_config_data(n->config_data); dnet_monitor_exit(n); free(n); }
int dnet_remove_local(struct dnet_node *n, struct dnet_id *id) { const size_t cmd_size = sizeof(struct dnet_cmd) + sizeof(struct dnet_io_attr); int err; char buffer[cmd_size]; struct dnet_cmd *cmd = (struct dnet_cmd *)buffer; struct dnet_io_attr *io = (struct dnet_io_attr *)(cmd + 1); memset(buffer, 0, cmd_size); cmd->id = *id; cmd->size = cmd_size - sizeof(struct dnet_cmd); cmd->flags = DNET_FLAGS_NOLOCK; cmd->cmd = DNET_CMD_DEL; io->flags = DNET_IO_FLAGS_SKIP_SENDING; memcpy(io->parent, id->id, DNET_ID_SIZE); memcpy(io->id, id->id, DNET_ID_SIZE); dnet_convert_io_attr(io); err = n->cb->command_handler(n->st, n->cb->command_private, cmd, io); dnet_log(n, DNET_LOG_NOTICE, "%s: local remove: err: %d.\n", dnet_dump_id(&cmd->id), err); return err; }
int dnet_monitor_init(struct dnet_node *n, struct dnet_config *cfg) { if (!cfg->monitor_port) { n->monitor = NULL; dnet_log(n, DNET_LOG_INFO, "Monitor hasn't been initialized because monitor port is zero\n"); return 0; } try { n->monitor = static_cast<void*>(new ioremap::monitor::monitor(n, cfg)); } catch (const std::exception &e) { dnet_log(n, DNET_LOG_ERROR, "Could not create monitor: %s\n", e.what()); return -ENOMEM; } return 0; }
static int dnet_check_number_of_copies(struct dnet_node *n, struct dnet_meta_container *mc, int *groups, int group_num, struct dnet_bulk_array *bulk_array, struct dnet_check_params *params) { struct dnet_id raw; int group_id = mc->id.group_id; int err = 0, i, error = 0; for (i=0; i<group_num; ++i) { if (groups[i] == group_id) continue; dnet_setup_id(&raw, groups[i], mc->id.id); err = dnet_bulk_add_id(n, bulk_array, &raw, mc, params); if (err) dnet_log(n, DNET_LOG_ERROR, "BULK: after adding ID %s err = %d\n", dnet_dump_id(&raw), err); if (!err) error = 0; else if (!error) error = err; } return error; }
int dnet_trans_alloc_send(struct dnet_session *s, struct dnet_trans_control *ctl) { struct dnet_node *n = s->node; struct dnet_net_state *st; struct dnet_addr *addr = NULL; int err; if (dnet_session_get_cflags(s) & DNET_FLAGS_DIRECT) { st = dnet_state_search_by_addr(n, &s->direct_addr); addr = &s->direct_addr; } else if(dnet_session_get_cflags(s) & DNET_FLAGS_FORWARD) { st = dnet_state_search_by_addr(n, &s->forward_addr); addr = &s->forward_addr; }else { st = dnet_state_get_first(n, &ctl->id); } if (!st) { dnet_log(n, DNET_LOG_ERROR, "%s: direct: %d, direct-addr: %s, forward: %d: trans_send: could not find network state for address", dnet_dump_id(&ctl->id), !!(dnet_session_get_cflags(s) & DNET_FLAGS_DIRECT), dnet_addr_string(&s->direct_addr), !!(dnet_session_get_cflags(s) & DNET_FLAGS_FORWARD)); err = dnet_trans_send_fail(s, addr, ctl, -ENXIO, 1); } else { err = dnet_trans_alloc_send_state(s, st, ctl); dnet_state_put(st); } return err; }
int dnet_locks_init(struct dnet_node *n, int num) { int err, i; n->locks = malloc(sizeof(struct dnet_locks) + num * sizeof(pthread_mutex_t)); if (!n->locks) { err = -ENOMEM; goto err_out_exit; } n->locks->num = num; for (i = 0; i < num; ++i) { err = pthread_mutex_init(&n->locks->lock[i], NULL); if (err) { err = -err; dnet_log(n, DNET_LOG_ERROR, "Could not create lock %d/%d: %s [%d]\n", i, num, strerror(-err), err); n->locks->num = i; goto err_out_destroy; } } return 0; err_out_destroy: dnet_locks_destroy(n); err_out_exit: return err; }
void dnet_server_node_destroy(struct dnet_node *n) { dnet_log(n, DNET_LOG_DEBUG, "Destroying server node."); /* * Monitor uses all others, so it should be stopped at first. */ dnet_monitor_exit(n); /* * Cache can be accessed from the io threads, so firstly stop them. * Cache uses backend to dump all ansynced data to the disk, so * backend must be destroyed the last. * * After all of them finish destroying the node, all it's counters and so on. */ dnet_node_cleanup_common_resources(n); dnet_route_list_destroy(n->route); n->route = NULL; dnet_backend_cleanup_all(n); dnet_srw_cleanup(n); dnet_counter_destroy(n); dnet_locks_destroy(n); dnet_local_addr_cleanup(n); dnet_notify_exit(n); if (n->config_data) n->config_data->destroy_config_data(n->config_data); free(n); }
void handler::async_write(std::string data) { auto self(shared_from_this()); m_report = std::move(data); dnet_log(m_monitor.node(), DNET_LOG_DEBUG, "monitor: server: send requested statistics: started: %s:%d, size: %lu", m_remote.c_str(), m_socket.remote_endpoint().port(), m_report.size()); boost::asio::async_write(m_socket, boost::asio::buffer(m_report), std::bind(&handler::handle_write, self)); }
static int dnet_check_merge(struct dnet_session *s, struct dnet_meta_container *mc) { struct dnet_node *n = s->node; int err; struct dnet_meta_container remote_mc; dnet_log(n, DNET_LOG_DEBUG, "in dnet_check_merge mc->size = %d\n", mc->size); memset(&remote_mc, 0, sizeof(struct dnet_meta_container)); err = dnet_read_meta(s, &remote_mc, NULL, 0, &mc->id); if (err) { if (err != -ENOENT) { dnet_log_raw(n, DNET_LOG_ERROR, "%s: failed to download object to be merged from storage: %d.\n", dnet_dump_id(&mc->id), err); goto err_out_exit; } dnet_log_raw(n, DNET_LOG_INFO, "%s: there is no meta in the storage to merge with, " "doing direct merge (plain upload).\n", dnet_dump_id(&mc->id)); err = dnet_merge_direct(s, mc); } else { err = dnet_merge_common(s, &remote_mc, mc); } if (err) goto err_out_exit; err_out_exit: if (remote_mc.data) free(remote_mc.data); return err; }
void dnet_server_node_destroy(struct dnet_node *n) { dnet_log(n, DNET_LOG_DEBUG, "Destroying server node.\n"); dnet_srw_cleanup(n); dnet_cache_cleanup(n); dnet_node_cleanup_common_resources(n); if (n->cb && n->cb->backend_cleanup) n->cb->backend_cleanup(n->cb->command_private); dnet_locks_destroy(n); dnet_local_addr_cleanup(n); dnet_notify_exit(n); if (n->config_data) { free(n->config_data->logger_value); free(n->config_data->cfg_addrs); free(n->config_data->cfg_remotes); free(n->config_data->cfg_backend); free(n->config_data); } free(n); }
/* * 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; }
int dnet_stat_local(struct dnet_net_state *st, struct dnet_id *id) { struct dnet_node *n = st->n; int size, cmd_size; struct dnet_cmd *cmd; struct dnet_io_attr *io; int err; size = 1; cmd_size = size + sizeof(struct dnet_cmd) + sizeof(struct dnet_io_attr); cmd = malloc(cmd_size); if (!cmd) { dnet_log(n, DNET_LOG_ERROR, "%s: failed to allocate %d bytes for local stat.\n", dnet_dump_id(id), cmd_size); err = -ENOMEM; goto err_out_exit; } memset(cmd, 0, cmd_size); io = (struct dnet_io_attr *)(cmd + 1); memcpy(&cmd->id, id, sizeof(struct dnet_id)); cmd->size = cmd_size - sizeof(struct dnet_cmd); cmd->flags = DNET_FLAGS_NOLOCK; cmd->cmd = DNET_CMD_READ; io->size = cmd->size - sizeof(struct dnet_io_attr); io->offset = 0; io->flags = DNET_IO_FLAGS_SKIP_SENDING; memcpy(io->parent, id->id, DNET_ID_SIZE); memcpy(io->id, id->id, DNET_ID_SIZE); dnet_convert_io_attr(io); err = n->cb->command_handler(st, n->cb->command_private, cmd, io); dnet_log(n, DNET_LOG_INFO, "%s: local stat: io_size: %llu, err: %d.\n", dnet_dump_id(&cmd->id), (unsigned long long)io->size, err); free(cmd); err_out_exit: return err; }
int dnet_check(struct dnet_node *n, struct dnet_meta_container *mc, struct dnet_bulk_array *bulk_array, int need_merge, struct dnet_check_params *params) { int err = 0; struct dnet_session *s = dnet_session_create(n); dnet_session_set_groups(s, (int *)&n->id.group_id, 1); dnet_log(n, DNET_LOG_DEBUG, "need_merge = %d, mc.size = %d\n", need_merge, mc->size); if (need_merge) { err = dnet_check_merge(s, mc); dnet_log(n, DNET_LOG_DEBUG, "err=%d\n", err); if (!err) dnet_merge_remove_local(n, &mc->id, 0); } else { err = dnet_check_copies(n, mc, bulk_array, params); } return err; }
struct dnet_meta_update *dnet_get_meta_update(struct dnet_node *n, struct dnet_meta_container *mc, struct dnet_meta_update *meta_update) { struct dnet_meta m; void *data = mc->data; uint32_t size = mc->size; struct dnet_meta_update *mu; int num; while (size) { if (size < sizeof(struct dnet_meta)) { dnet_log(n, DNET_LOG_ERROR, "Metadata size %u is too small, min %zu, searching for type 0x%x.\n", size, sizeof(struct dnet_meta), DNET_META_UPDATE); return NULL; } m = *(struct dnet_meta *)data; dnet_convert_meta(&m); if (m.size + sizeof(struct dnet_meta) > size) { dnet_log(n, DNET_LOG_ERROR, "Metadata entry broken: entry size %u, type: 0x%x, struct size: %zu, " "total size left: %u, searching for type: 0x%x.\n", m.size, m.type, sizeof(struct dnet_meta), size, DNET_META_UPDATE); return NULL; } if (m.type == DNET_META_UPDATE) { mu = (struct dnet_meta_update *)(data + sizeof(struct dnet_meta)); num = m.size / sizeof(struct dnet_meta_update); if (num >= 0) { if (meta_update) { memcpy(meta_update, &mu[0], sizeof(struct dnet_meta_update)); dnet_convert_meta_update(meta_update); } return &mu[0]; } } data += m.size + sizeof(struct dnet_meta); size -= m.size + sizeof(struct dnet_meta); } return NULL; }
int dnet_remove_local(struct dnet_node *n, struct dnet_id *id) { int cmd_size; struct dnet_cmd *cmd; struct dnet_io_attr *io; int err; cmd_size = sizeof(struct dnet_cmd) + sizeof(struct dnet_io_attr); cmd = malloc(cmd_size); if (!cmd) { dnet_log(n, DNET_LOG_ERROR, "%s: failed to allocate %d bytes for local remove.\n", dnet_dump_id(id), cmd_size); err = -ENOMEM; goto err_out_exit; } memset(cmd, 0, cmd_size); io = (struct dnet_io_attr *)(cmd + 1); cmd->id = *id; cmd->size = cmd_size - sizeof(struct dnet_cmd); cmd->flags = DNET_FLAGS_NOLOCK; cmd->cmd = DNET_CMD_DEL; io->flags = DNET_IO_FLAGS_SKIP_SENDING; memcpy(io->parent, id->id, DNET_ID_SIZE); memcpy(io->id, id->id, DNET_ID_SIZE); dnet_convert_io_attr(io); err = n->cb->command_handler(n->st, n->cb->command_private, cmd, io); dnet_log(n, DNET_LOG_NOTICE, "%s: local remove: err: %d.\n", dnet_dump_id(&cmd->id), err); free(cmd); err_out_exit: return err; }
void dnet_trans_remove_nolock(struct dnet_net_state *st, struct dnet_trans *t) { if (!t->trans_entry.rb_parent_color) { dnet_log(st->n, DNET_LOG_ERROR, "%s: trying to remove out-of-trans-tree transaction %llu.", dnet_dump_id(&t->cmd.id), (unsigned long long)t->trans); return; } rb_erase(&t->trans_entry, &st->trans_root); t->trans_entry.rb_parent_color = 0; dnet_trans_remove_timer_nolock(st, t); }
void unlock() { m_guard.unlock(); dnet_log_level level = DNET_LOG_DEBUG; if (m_timer.elapsed() > 100) level = DNET_LOG_ERROR; if (m_timer.elapsed() > 0) { dnet_log(m_node, level, "%s: cache lock: unlock: %lld ms", m_name, m_timer.elapsed()); } m_timer.restart(); }
void dnet_server_node_destroy(struct dnet_node *n) { dnet_log(n, DNET_LOG_DSA, "Destroying server node at %s, st: %p.\n", dnet_dump_node(n), n->st); n->need_exit = 1; dnet_srw_cleanup(n); dnet_locks_destroy(n); dnet_notify_exit(n); dnet_node_destroy(n); }
void dnet_monitor_stats_update(struct dnet_node *n, const struct dnet_cmd *cmd, const int err, const int cache, const uint32_t size, const unsigned long time) { try { auto real_monitor = ioremap::monitor::get_monitor(n); if (real_monitor) { real_monitor->get_statistics().command_counter(cmd->cmd, cmd->trans, err, cache, size, time); auto top_stats = real_monitor->get_statistics().get_top_stats(); if (top_stats) { top_stats->update_stats(cmd, size); } } } catch (const std::exception &e) { dnet_log(n, DNET_LOG_DEBUG, "monitor: failed to update stats: %s", e.what()); } }
void dnet_server_node_destroy(struct dnet_node *n) { dnet_log(n, DNET_LOG_DEBUG, "Destroying server node at %s, st: %p.\n", dnet_dump_node(n), n->st); dnet_srw_cleanup(n); dnet_node_cleanup_common_resources(n); if (n->cb && n->cb->backend_cleanup) n->cb->backend_cleanup(n->cb->command_private); dnet_locks_destroy(n); dnet_notify_exit(n); free(n); }
void handler::handle_read(const boost::system::error_code &err, size_t size) { if (err) { close(); return; } auto req = parse_request(size); std::string content = ""; if (req > 0) { dnet_log(m_monitor.node(), DNET_LOG_DEBUG, "monitor: server: got statistics request for categories: %lx from: %s:%d", req, m_remote.c_str(), m_socket.remote_endpoint().port()); content = m_monitor.get_statistics().report(req); } std::string reply = make_reply(req, content); async_write(reply); }
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; }
int process_find_indexes(dnet_net_state *state, dnet_cmd *cmd, dnet_indexes_request *request) { local_session sess(state->n); const bool intersection = request->flags & DNET_INDEXES_FLAGS_INTERSECT; const bool unite = request->flags & DNET_INDEXES_FLAGS_UNITE; dnet_log(state->n, DNET_LOG_DEBUG, "INDEXES_FIND: indexes count: %u, flags: %llu\n", (unsigned) request->entries_count, (unsigned long long) request->flags); if (intersection && unite) { return -ENOTSUP; } std::vector<find_indexes_result_entry> result; std::map<dnet_raw_id, size_t, dnet_raw_id_less_than<> > result_map; dnet_indexes tmp; int err = -1; dnet_id id = cmd->id; size_t data_offset = 0; char *data_start = reinterpret_cast<char *>(request->entries); for (uint64_t i = 0; i < request->entries_count; ++i) { dnet_indexes_request_entry &request_entry = *reinterpret_cast<dnet_indexes_request_entry *>(data_start + data_offset); data_offset += sizeof(dnet_indexes_request_entry) + request_entry.size; memcpy(id.id, request_entry.id.id, sizeof(id.id)); int ret = 0; data_pointer data = sess.read(id, &ret); if (ret) { dnet_log(state->n, DNET_LOG_DEBUG, "%s: INDEXES_FIND, err: %d\n", dnet_dump_id(&id), ret); } if (ret && unite) { if (err != -1) err = ret; continue; } else if (ret && intersection) { return ret; } err = 0; tmp.indexes.clear(); indexes_unpack(state->n, &id, data, &tmp, "process_find_indexes"); if (unite) { for (size_t j = 0; j < tmp.indexes.size(); ++j) { const index_entry &entry = tmp.indexes[j]; auto it = result_map.find(entry.index); if (it == result_map.end()) { it = result_map.insert(std::make_pair(entry.index, result.size())).first; result.resize(result.size() + 1); result.back().id = entry.index; } result[it->second].indexes.emplace_back(request_entry.id, entry.data); } } else if (intersection && i == 0) { result.resize(tmp.indexes.size()); for (size_t j = 0; j < tmp.indexes.size(); ++j) { find_indexes_result_entry &entry = result[j]; entry.id = tmp.indexes[j].index; entry.indexes.emplace_back( request_entry.id, tmp.indexes[j].data); } } else if (intersection) { // Remove all objects from result, which are not presented for this index auto it = std::set_intersection(result.begin(), result.end(), tmp.indexes.begin(), tmp.indexes.end(), result.begin(), dnet_raw_id_less_than<skip_data>()); result.resize(it - result.begin()); // Remove all objects from this index, which are not presented in result std::set_intersection(tmp.indexes.begin(), tmp.indexes.end(), result.begin(), result.end(), tmp.indexes.begin(), dnet_raw_id_less_than<skip_data>()); // As lists contain othe same objects - it's possible to add index data by one cycle auto jt = tmp.indexes.begin(); for (auto kt = result.begin(); kt != result.end(); ++kt, ++jt) { kt->indexes.emplace_back(request_entry.id, jt->data); } } } // if (err != 0) // return err; dnet_log(state->n, DNET_LOG_DEBUG, "%s: INDEXES_FIND: result of find: %zu objects\n", dnet_dump_id(&id), result.size()); msgpack::sbuffer buffer; msgpack::pack(&buffer, result); cmd->flags &= ~DNET_FLAGS_NEED_ACK; dnet_send_reply(state, cmd, buffer.data(), buffer.size(), 0); return err; }