1#include <Common/Config/ConfigProcessor.h>
2#include <Common/ZooKeeper/ZooKeeper.h>
3#include <Poco/Event.h>
4#include <iostream>
5
6/// A tool for reproducing https://issues.apache.org/jira/browse/ZOOKEEPER-706
7/// Original libzookeeper can't reconnect the session if the length of SET_WATCHES message
8/// exceeds jute.maxbuffer (0xfffff by default).
9/// This happens when the number of watches exceeds ~29000.
10///
11/// Session reconnect can be caused by forbidding packets to the current zookeeper server, e.g.
12/// sudo ip6tables -A OUTPUT -d mtzoo01it.haze.yandex.net -j REJECT
13
14const size_t N_THREADS = 100;
15
16int main(int argc, char ** argv)
17{
18 try
19 {
20 if (argc != 3)
21 {
22 std::cerr << "usage: " << argv[0] << " <zookeeper_config> <number_of_watches>" << std::endl;
23 return 3;
24 }
25
26 DB::ConfigProcessor processor(argv[1], false, true);
27 auto config = processor.loadConfig().configuration;
28 zkutil::ZooKeeper zk(*config, "zookeeper");
29 zkutil::EventPtr watch = std::make_shared<Poco::Event>();
30
31 /// NOTE: setting watches in multiple threads because doing it in a single thread is too slow.
32 size_t watches_per_thread = std::stoull(argv[2]) / N_THREADS;
33 std::vector<std::thread> threads;
34 for (size_t i_thread = 0; i_thread < N_THREADS; ++i_thread)
35 {
36 threads.emplace_back([&, i_thread]
37 {
38 for (size_t i = 0; i < watches_per_thread; ++i)
39 zk.exists("/clickhouse/nonexistent_node" + std::to_string(i * N_THREADS + i_thread), nullptr, watch);
40 });
41 }
42 for (size_t i_thread = 0; i_thread < N_THREADS; ++i_thread)
43 threads[i_thread].join();
44
45 while (true)
46 {
47 std::cerr << "WAITING..." << std::endl;
48 sleep(10);
49 }
50 }
51 catch (Poco::Exception & e)
52 {
53 std::cerr << "Exception: " << e.displayText() << std::endl;
54 return 1;
55 }
56 catch (std::exception & e)
57 {
58 std::cerr << "std::exception: " << e.what() << std::endl;
59 return 3;
60 }
61 catch (...)
62 {
63 std::cerr << "Some exception" << std::endl;
64 return 2;
65 }
66}
67