tarantool/tntcxx

Connection hangs if Tarantool's `readahead` limit is reached

Closed this issue · 0 comments

Consider the following server setup and connector usage:

os.execute('rm -rf *.snap *.xlog *.vylog 512')

console = require('console')

box.cfg{listen = 3301, memtx_memory = 1024*1024*1024, wal_mode = 'none', readahead = 65536}

box.once('bootstrap', function()
    local s = box.schema.space.create('tester', {if_not_exists = true})
    s:format({{name = 'id', type = 'unsigned'}})
    s:create_index('primary', {type = 'tree', parts = {'id'}, if_not_exists = true})
    box.schema.user.grant('guest', 'read,write,execute', 'universe', nil, {if_not_exists = true})
end)

console.start()

os.exit()
#include <array>
#include <random>
#include <limits>
#include <vector>

#include "src/Client/Connector.hpp"
#include "src/Buffer/Buffer.hpp"

const char *address = "127.0.0.1";
int port = 3301;

using Buf_t = tnt::Buffer<16 * 1024>;
using Net_t = LibevNetProvider<Buf_t, DefaultStream>;

constexpr std::size_t field_count = 1000;
constexpr std::size_t reqs_count = 1000;

constexpr std::uint32_t space_id = 512;

int
main()
{
	Connector<Buf_t, Net_t> client;
	Connection<Buf_t, Net_t> conn(client);

	int rc = client.connect(conn, {
		.address = address,
		.service = std::to_string(port),
	});
	if (rc != 0) {
		std::cerr << conn.getError().msg << std::endl;
		return EXIT_FAILURE;
	}

	rid_t ping = conn.ping();
	if (client.wait(conn, ping) != 0) {
		std::cerr << conn.getError().msg << std::endl;
		return EXIT_FAILURE;
	}
	std::optional<Response<Buf_t>> response = conn.getResponse(ping);
	assert(response != std::nullopt);

	std::default_random_engine rng{std::random_device()()};
	std::uniform_int_distribution<std::uint64_t> values(0, std::numeric_limits<uint64_t>::max());

	std::array<std::vector<std::uint64_t>, reqs_count> reqs;
	for (std::size_t i = 0; i < reqs_count; ++i) {
		reqs[i].reserve(field_count);
		reqs[i].push_back(i + 1);
		for (std::size_t k = 1; k < field_count; ++k) {
			reqs[i].push_back(values(rng));
		}
	}

	std::vector<rid_t> futures(reqs_count);
	for (std::size_t i = 0; i < reqs_count; ++i) {
		futures[i] = conn.space[space_id].replace(reqs[i]);
	}
	client.waitAll(conn, futures);
	for (const auto &future : futures) {
		assert(conn.futureIsReady(future));
		response = conn.getResponse(future);
		assert(response != std::nullopt);
	}

	client.close(conn);
}

Actual behavior

The script hangs.

Expected behavior

The script successfully executes.