void slicer::request_slice()

in src/native/diffs/core/slicer.cpp [42:137]


void slicer::request_slice(std::shared_ptr<prepared_item> &to_slice, uint64_t offset, const item_definition &slice)
{
	// we shouldn't be trying to slice hashes out of a thing
	// when we don't know the hash and can't verify it
	if (!slice.has_any_hashes())
	{
		throw errors::user_exception(
			errors::error_code::diff_slicing_request_slice_no_hash, "Trying to hash item with no hash.");
	}

	// printf("slicer::request_slice() for: %s\n", slice.to_string().c_str());
	std::lock_guard<std::mutex> state_lock_guard{m_state_mutex};

	if (m_state != slicing_state::paused)
	{
		throw errors::user_exception(
			errors::error_code::diff_slicing_invalid_state,
			"slicer::request_slice: Expected slicing state to be paused, actual: " + std::to_string((int)m_state));
	}

	std::lock_guard<std::mutex> request_lock_guard{m_request_mutex};

	// Add an entry about the request we're making
	if (m_slice_item_request_counts.count(slice) != 0)
	{
		ADU_LOG("slicer::request_slice: Already have a request for this item: {}", slice.to_string());
		//  There's already a pending request for a matching slice
		//  make one more request and bail
		m_slice_item_request_counts[slice]++;
		return;
	}

	auto item_to_slice = to_slice->get_item_definition();

	if (m_item_to_slice_prepared.count(item_to_slice) == 0)
	{
		m_item_to_slice_prepared.insert(std::pair{item_to_slice, to_slice});
	}

	if (m_items_to_slices_requested.count(item_to_slice) == 0)
	{
		auto new_map = std::make_unique<offset_to_item_map>();
		new_map->insert(std::pair{offset, slice});
		m_items_to_slices_requested.insert(std::pair{item_to_slice, std::move(new_map)});
		m_slice_item_request_counts.insert(std::pair{slice, 1});
		return;
	}

	auto &offset_to_slice_map = *(m_items_to_slices_requested[item_to_slice].get());

	ADU_LOG("slicer::request_slice: Adding entry for offset: {}, for item: {}", offset, slice.to_string());

	// check that we're not overlapping with the previous result
	if (offset_to_slice_map.size() != 0)
	{
		// lower_bound is first offset that is not < offset, it is >= our offset
		auto lower_bound = offset_to_slice_map.lower_bound(offset);

		if (lower_bound != offset_to_slice_map.cend())
		{
			uint64_t lower_bound_offset = lower_bound->first;
			uint64_t lower_bound_length = lower_bound->second.size();

			if (!check_overlap(offset, slice.size(), lower_bound_offset, lower_bound_length))
			{
				std::string msg = "slicer::request_slice: Found overlap with slices. ";
				msg += "offset: " + std::to_string(offset);
				msg += ", length: " + std::to_string(slice.size());
				msg += ", lower_bound_offset: " + std::to_string(lower_bound_offset);
				msg += ", lower_bound_length: " + std::to_string(lower_bound_length);
				throw errors::user_exception(errors::error_code::diff_slicing_request_slice_overlap, msg);
			}
		}

		if (lower_bound != offset_to_slice_map.cbegin())
		{
			lower_bound--;

			uint64_t prev_offset = lower_bound->first;
			uint64_t prev_length = lower_bound->second.size();

			if (!check_overlap(offset, slice.size(), prev_offset, prev_length))
			{
				std::string msg = "slicer::request_slice: Found overlap with slices. ";
				msg += "offset: " + std::to_string(offset);
				msg += ", length: " + std::to_string(slice.size());
				msg += ", prev offset: " + std::to_string(prev_offset);
				msg += ", prev length: " + std::to_string(prev_length);
				throw errors::user_exception(errors::error_code::diff_slicing_request_slice_overlap, msg);
			}
		}
	}

	m_slice_item_request_counts.insert(std::pair{slice, 1});
	offset_to_slice_map.insert(std::pair{offset, slice});
}