Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Library leaks sockets when it cannot connect to the database #208

@Akvinikym

Description

@Akvinikym

Hello.

I have a minimal example of the (I assume) correct usage of the library which leads to sockets being leaked by it. Steps to reproduce:

  1. Get the clickhouse-server up
  2. Run this program:
#include <clickhouse/client.h>
#include <thread>

int main()
{
	clickhouse::Client client(clickhouse::ClientOptions().SetHost("localhost").SetPort(9000).SetUser("default").SetPassword("clickhouse"));
	client.Execute("CREATE DATABASE IF NOT EXISTS test");
	client.Execute("CREATE TABLE IF NOT EXISTS test.numbers (id UInt64) ENGINE = Memory");

	bool error_happened = false;
	uint64_t i = 0;
	while (true)
	{
		std::this_thread::sleep_for(std::chrono::seconds(1));

		try
		{
			if (error_happened)
			{
				// doing it here and not in catch block because if ResetConnection() fails,
				// it will throw another exception, leading to program finish
				client.ResetConnection();
				error_happened = false;
			}

			clickhouse::Block block;
			auto id_column = std::make_shared<clickhouse::ColumnUInt64>();
			id_column->Append(i);
			block.AppendColumn("id", id_column);
			client.Insert("test.numbers", block);
		}
		catch (const std::exception& e)
		{
			printf("exception: %s\n", e.what());
			error_happened = true;
		}

		++i;
	}
}
  1. Take a look at the number of sockets used by the program (it will be equal to 1), for example, by executing the command:
ls -la /proc/${PID}/fd | grep socket | wc -l
  1. Stop the clickhouse-server
  2. Execute the command from step 3 to see number of socket files rising up to infinity (or the OS hard limit)
  3. Get the clickhouse-server up again
  4. Program will successfully reconnect and continue sending data, but the number of used sockets will remain at the same level

I think this issue happens because in function SocketConnect(..) the socket is created on line 126, but if connect(..) on line 134 fails, close(..) is never called for this socket object, which is required according to the documentation (see NOTES section).

If I add close(..) calls before lines 149 and 166, the program stops leaking sockets and is executed successfully. I could have made a PR for those changes, but I'm not sure they're correct or enough to cover all cases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority-highPretty important bug or issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions