コード例 #1
0
ファイル: indexes.cpp プロジェクト: SaveTheRbtz/elliptics
/*!
 * Update data-object table for certain secondary index.
 *
 * @index_data is what client provided
 * @data is what was downloaded from the storage
 */
data_pointer convert_index_table(dnet_node *node, dnet_id *cmd_id, dnet_indexes_request *request,
	const data_pointer &index_data, const data_pointer &data, update_index_action action)
{
	dnet_indexes indexes;
	if (!data.empty())
		indexes_unpack(node, cmd_id, data, &indexes, "convert_index_table");

	// Construct index entry
	index_entry request_index;
	memcpy(request_index.index.id, request->id.id, sizeof(request_index.index.id));
	request_index.data = index_data;

	auto it = std::lower_bound(indexes.indexes.begin(), indexes.indexes.end(),
		request_index, dnet_raw_id_less_than<skip_data>());
	if (it != indexes.indexes.end() && it->index == request_index.index) {
		// It's already there
		if (action == insert_data) {
			if (it->data == request_index.data) {
				// All's ok, keep it untouched
				return data;
			} else {
				// Data is not correct, replace it by new one
				it->data = request_index.data;
			}
		} else {
			// Anyway, destroy it
			indexes.indexes.erase(it);
		}
	} else {
		// Index is not created yet
		if (action == insert_data) {
			// Just insert it
			indexes.indexes.insert(it, 1, request_index);
		} else {
			// All's ok, keep it untouched
			return data;
		}
	}

	indexes.shard_id = request->shard_id;
	indexes.shard_count = request->shard_count;

	msgpack::sbuffer buffer;
	msgpack::pack(&buffer, indexes);

	data_buffer new_buffer(DNET_INDEX_TABLE_MAGIC_SIZE + buffer.size());
	new_buffer.write(dnet_bswap64(DNET_INDEX_TABLE_MAGIC));
	new_buffer.write(buffer.data(), buffer.size());

	return std::move(new_buffer);
}
コード例 #2
0
ファイル: indexes.cpp プロジェクト: SaveTheRbtz/elliptics
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;
}
コード例 #3
0
ファイル: indexes.cpp プロジェクト: loqutus/elliptics
/*!
 * Update data-object table for certain secondary index.
 *
 * @index_data is what client provided
 * @data is what was downloaded from the storage
 */
data_pointer convert_index_table(dnet_node *node, dnet_id *cmd_id, const dnet_indexes_request *request,
	const data_pointer &index_data, const data_pointer &data, uint32_t action,
	std::vector<dnet_indexes_reply_entry> * &removed, uint32_t limit)
{
	elliptics_timer timer;

	dnet_indexes indexes;
	if (!data.empty())
		indexes_unpack(node, cmd_id, data, &indexes, "convert_index_table");

	const int64_t timer_unpack = timer.restart();

	// Construct index entry
	dnet_index_entry request_index;
	memcpy(request_index.index.id, request->id.id, sizeof(request_index.index.id));
	request_index.data = index_data;
	dnet_current_time(&request_index.time);

	auto it = std::lower_bound(indexes.indexes.begin(), indexes.indexes.end(), request_index, dnet_raw_id_less_than<skip_data>());

	const int64_t timer_lower_bound = timer.restart();

	if (it != indexes.indexes.end() && it->index == request_index.index) {
		// It's already there
		if (action == DNET_INDEXES_FLAGS_INTERNAL_INSERT) {
			// Item exists, update it's data and time if it's capped collection
			if (!removed && it->data == request_index.data) {
				const int64_t timer_compare = timer.restart();
				DNET_DUMP_ID_LEN(id_str, cmd_id, DNET_DUMP_NUM);
				typedef long long int lld;
				dnet_log(node, DNET_LOG_INFO, "INDEXES_INTERNAL: convert: id: %s, data size: %zu, new data size: %zu,"
					 "unpack: %lld ms, lower_bound: %lld ms, compare: %lld ms\n",
					 id_str, data.size(), data.size(), lld(timer_unpack), lld(timer_lower_bound),
					 lld(timer_compare));
				// All's ok, keep it untouched
				return data;
			}
			it->data = request_index.data;
			it->time = request_index.time;
		} else {
			// Anyway, destroy it
			indexes.indexes.erase(it);
		}
	} else {
		// Index is not created yet
		if (action == DNET_INDEXES_FLAGS_INTERNAL_INSERT) {
			// Remove extra elements from capped collection
			if (removed && limit != 0 && indexes.indexes.size() + 1 > limit) {
				dnet_indexes_reply_entry entry;
				memset(&entry, 0, sizeof(entry));

				auto position = it - indexes.indexes.begin();

				while (indexes.indexes.size() + 1 > limit && !indexes.indexes.empty()) {
					auto jt = std::min_element(indexes.indexes.begin(), indexes.indexes.end(), entry_time_less_than);

					// jt will be removed, so it should be modified to be still valid
					if (position > jt - indexes.indexes.begin())
						--position;

					memcpy(entry.id.id, jt->index.id, DNET_ID_SIZE);
					entry.status = DNET_INDEXES_CAPPED_REMOVED;

					indexes.indexes.erase(jt);
					removed->push_back(entry);
				}

				it = indexes.indexes.begin() + position;
			}
			// And just insert new index
			indexes.indexes.insert(it, 1, request_index);
		} else {
			const int64_t timer_compare = timer.restart();
			DNET_DUMP_ID_LEN(id_str, cmd_id, DNET_DUMP_NUM);
			typedef long long int lld;
			dnet_log(node, DNET_LOG_INFO, "INDEXES_INTERNAL: convert: id: %s, data size: %zu, new data size: %zu,"
				 "unpack: %lld ms, lower_bound: %lld ms, compare: %lld ms\n",
				 id_str, data.size(), data.size(), lld(timer_unpack), lld(timer_lower_bound),
				 lld(timer_compare));
			// All's ok, keep it untouched
			return data;
		}
	}

	const int64_t timer_update = timer.restart();

	indexes.shard_id = request->shard_id;
	indexes.shard_count = request->shard_count;

	msgpack::sbuffer buffer;
	msgpack::pack(&buffer, indexes);

	const int64_t timer_pack = timer.restart();

	data_buffer new_buffer(DNET_INDEX_TABLE_MAGIC_SIZE + buffer.size());
	new_buffer.write(dnet_bswap64(DNET_INDEX_TABLE_MAGIC));
	new_buffer.write(buffer.data(), buffer.size());

	const int64_t timer_write = timer.restart();

	DNET_DUMP_ID_LEN(id_str, cmd_id, DNET_DUMP_NUM);
	typedef long long int lld;
	dnet_log(node, DNET_LOG_INFO, "INDEXES_INTERNAL: convert: id: %s, data size: %zu, new data size: %zu,"
		 "unpack: %lld ms, lower_bound: %lld ms, update: %lld ms, pack: %lld ms, write: %lld ms\n",
		 id_str, data.size(), new_buffer.size(), lld(timer_unpack), lld(timer_lower_bound),
		 lld(timer_update), lld(timer_pack), lld(timer_write));

	return std::move(new_buffer);
}
コード例 #4
0
ファイル: indexes.cpp プロジェクト: loqutus/elliptics
int process_find_indexes(dnet_net_state *state, dnet_cmd *cmd, const dnet_id &request_id, dnet_indexes_request *request, bool more)
{
	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, more: %d\n",
		 (unsigned) request->entries_count, (unsigned long long) request->flags, int(more));

	if ((intersection && unite) || !(intersection || unite)) {
		return -EINVAL;
	}

	std::vector<find_indexes_result_entry> result;
	std::vector<data_pointer> data_cache;

	std::map<dnet_raw_id, size_t, dnet_raw_id_less_than<> > result_map;

	dnet_indexes tmp;

	int err = -1;
	dnet_id id = request_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);
		data_cache.push_back(data);

		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 auto &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;
				}

				index_entry result_entry = { request_entry.id, entry.data };
				result[it->second].indexes.push_back(result_entry);
			}
		} else if (intersection && i == 0) {
			result.resize(tmp.indexes.size());
			for (size_t j = 0; j < tmp.indexes.size(); ++j) {
				auto &entry = result[j];
				entry.id = tmp.indexes[j].index;
				index_entry result_entry = { request_entry.id, tmp.indexes[j].data };
				entry.indexes.push_back(result_entry);
			}
		} 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) {
				index_entry result_entry = { request_entry.id, jt->data };
				kt->indexes.push_back(result_entry);
			}
		}
	}

	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);

	if (!more) {
		/*
		 * Unset NEED_ACK flag if and only if it is the last reply.
		 * We have to send positive reply in such case, also we don't want to send
		 * useless acknowledge packet.
		 */
		cmd->flags &= ~DNET_FLAGS_NEED_ACK;
	}
	dnet_cmd cmd_copy = *cmd;
	dnet_setup_id(&cmd_copy.id, cmd->id.group_id, request_id.id);
	dnet_send_reply(state, &cmd_copy, buffer.data(), buffer.size(), more);

	return err;
}
コード例 #5
0
ファイル: indexes.cpp プロジェクト: kod3r/elliptics
/*!
 * Update data-object table for certain secondary index.
 *
 * @index_data is what client provided
 * @data is what was downloaded from the storage
 */
data_pointer convert_index_table(dnet_node *node, dnet_id *cmd_id, dnet_indexes_request *request,
	const data_pointer &index_data, const data_pointer &data, update_index_action action)
{
	elliptics_timer timer;

	raw_dnet_indexes indexes;
	if (!data.empty())
		indexes_unpack(node, cmd_id, data, &indexes, "convert_index_table");

	const int64_t timer_unpack = timer.restart();

	// Construct index entry
	raw_index_entry request_index;
	memcpy(request_index.index.id, request->id.id, sizeof(request_index.index.id));
	request_index.data.data = index_data.data();
	request_index.data.size = index_data.size();

	auto it = std::lower_bound(indexes.indexes.begin(), indexes.indexes.end(), request_index);

	const int64_t timer_lower_bound = timer.restart();

	if (it != indexes.indexes.end() && it->index == request_index.index) {
		// It's already there
		if (action == insert_data) {
			if (it->data == request_index.data) {
				const int64_t timer_compare = timer.restart();
				DNET_DUMP_ID_LEN(id_str, cmd_id, DNET_DUMP_NUM);
				typedef long long int lld;
				dnet_log(node, DNET_LOG_INFO, "INDEXES_INTERNAL: convert: id: %s, data size: %zu, new data size: %zu,"
					 "unpack: %lld ms, lower_bound: %lld ms, compare: %lld ms\n",
					 id_str, data.size(), data.size(), lld(timer_unpack), lld(timer_lower_bound),
					 lld(timer_compare));
				// All's ok, keep it untouched
				return data;
			} else {
				// Data is not correct, replace it by new one
				it->data = request_index.data;
			}
		} else {
			// Anyway, destroy it
			indexes.indexes.erase(it);
		}
	} else {
		// Index is not created yet
		if (action == insert_data) {
			// Just insert it
			indexes.indexes.insert(it, 1, request_index);
		} else {
			const int64_t timer_compare = timer.restart();
			DNET_DUMP_ID_LEN(id_str, cmd_id, DNET_DUMP_NUM);
			typedef long long int lld;
			dnet_log(node, DNET_LOG_INFO, "INDEXES_INTERNAL: convert: id: %s, data size: %zu, new data size: %zu,"
				 "unpack: %lld ms, lower_bound: %lld ms, compare: %lld ms\n",
				 id_str, data.size(), data.size(), lld(timer_unpack), lld(timer_lower_bound),
				 lld(timer_compare));
			// All's ok, keep it untouched
			return data;
		}
	}

	const int64_t timer_update = timer.restart();

	indexes.shard_id = request->shard_id;
	indexes.shard_count = request->shard_count;

	msgpack::sbuffer buffer;
	msgpack::pack(&buffer, indexes);

	const int64_t timer_pack = timer.restart();

	data_buffer new_buffer(DNET_INDEX_TABLE_MAGIC_SIZE + buffer.size());
	new_buffer.write(dnet_bswap64(DNET_INDEX_TABLE_MAGIC));
	new_buffer.write(buffer.data(), buffer.size());

	const int64_t timer_write = timer.restart();

	DNET_DUMP_ID_LEN(id_str, cmd_id, DNET_DUMP_NUM);
	typedef long long int lld;
	dnet_log(node, DNET_LOG_INFO, "INDEXES_INTERNAL: convert: id: %s, data size: %zu, new data size: %zu,"
		 "unpack: %lld ms, lower_bound: %lld ms, update: %lld ms, pack: %lld ms, write: %lld ms\n",
		 id_str, data.size(), new_buffer.size(), lld(timer_unpack), lld(timer_lower_bound),
		 lld(timer_update), lld(timer_pack), lld(timer_write));

	return std::move(new_buffer);
}