diff --git a/cloud/blockstore/config/server.proto b/cloud/blockstore/config/server.proto index 719f5ef5dd0..3d95887a600 100644 --- a/cloud/blockstore/config/server.proto +++ b/cloud/blockstore/config/server.proto @@ -183,7 +183,7 @@ message TServerConfig // NBD request timeout in seconds, only makes sense if using netlink optional uint32 NbdRequestTimeout = 112; - // NBD connection timeout in seconds, only makes sense if using netlink + // NBD connection timeout in seconds optional uint32 NbdConnectionTimeout = 113; // Endpoint Proxy unix socket path. Triggers proxy device factory usage diff --git a/cloud/blockstore/libs/daemon/common/bootstrap.cpp b/cloud/blockstore/libs/daemon/common/bootstrap.cpp index 84b804fa93b..959edc2a701 100644 --- a/cloud/blockstore/libs/daemon/common/bootstrap.cpp +++ b/cloud/blockstore/libs/daemon/common/bootstrap.cpp @@ -552,10 +552,13 @@ void TBootstrapBase::Init() EndpointProxyClient); } + // The only case we want kernel to retry requests is when the socket is dead + // due to nbd server restart. And since we can't configure ioctl device to + // use a new socket, request timeout effectively becomes connection timeout if (!nbdDeviceFactory) { nbdDeviceFactory = NBD::CreateDeviceFactory( Logging, - TDuration::Days(1)); // timeout + Configs->ServerConfig->GetNbdConnectionTimeout()); // timeout } EndpointManager = CreateEndpointManager( diff --git a/cloud/blockstore/libs/endpoint_proxy/server/server.cpp b/cloud/blockstore/libs/endpoint_proxy/server/server.cpp index 1cdb82c9962..3cce7f2f3ec 100644 --- a/cloud/blockstore/libs/endpoint_proxy/server/server.cpp +++ b/cloud/blockstore/libs/endpoint_proxy/server/server.cpp @@ -575,8 +575,6 @@ struct TServer: IEndpointProxyServer Scheduler, ep.RequestStats, volumeStats); - - ep.Client->Start(); STORAGE_INFO(request.ShortDebugString().Quote() << " - Started DurableClient"); @@ -635,18 +633,19 @@ struct TServer: IEndpointProxyServer TDuration::Days(1), // connection timeout true); // reconfigure device if exists } else { - // For netlink devices we have to balance request timeout between - // time it takes to fail request for good and resend it if socket - // is dead due to proxy restart. We can't configure ioctl device - // to use a fresh socket, so there is no point configuring it + // The only case we want kernel to retry requests is when the socket + // is dead due to nbd server restart. And since we can't configure + // ioctl device to use a new socket, request timeout effectively + // becomes connection timeout ep.NbdDevice = NBD::CreateDevice( Logging, *ep.ListenAddress, request.GetNbdDevice(), - TDuration::Days(1)); // request timeout + TDuration::Days(1)); // timeout } - auto status = ep.NbdDevice->Start().ExtractValue(); + auto future = ep.NbdDevice->Start(); + const auto& status = future.GetValue(); if (HasError(status)) { STORAGE_ERROR(request.ShortDebugString().Quote() << " - Unable to start nbd device: " diff --git a/cloud/blockstore/libs/nbd/netlink_device.cpp b/cloud/blockstore/libs/nbd/netlink_device.cpp index 07176cca60b..6e9bd52779f 100644 --- a/cloud/blockstore/libs/nbd/netlink_device.cpp +++ b/cloud/blockstore/libs/nbd/netlink_device.cpp @@ -19,6 +19,8 @@ namespace { using namespace NThreading; +using TResponseHandler = std::function; + //////////////////////////////////////////////////////////////////////////////// constexpr TStringBuf NBD_DEVICE_SUFFIX = "/dev/nbd"; @@ -62,14 +64,49 @@ class TNetlinkSocket nl_socket_free(Socket); } - operator nl_sock*() const + int GetFamily() const { - return Socket; + return Family; } - int GetFamily() const + template + void SetCallback(nl_cb_type type, F func) { - return Family; + auto arg = std::make_unique(std::move(func)); + + if (int err = nl_socket_modify_cb( + Socket, + type, + NL_CB_CUSTOM, + TNetlinkSocket::ResponseHandler, + arg.get())) + { + throw TServiceError(E_FAIL) + << "unable to set socket callback: " << nl_geterror(err); + } + arg.release(); + } + + static int ResponseHandler(nl_msg* msg, void* arg) + { + auto func = std::unique_ptr( + static_cast(arg)); + + return (*func)(static_cast(nlmsg_data(nlmsg_hdr(msg)))); + } + + void Send(nl_msg* message) + { + if (int err = nl_send_auto(Socket, message); err < 0) { + throw TServiceError(E_FAIL) + << "send error: " << nl_geterror(err); + } + if (int err = nl_wait_for_ack(Socket)) { + // this is either recv error, or an actual error message received + // from the kernel + throw TServiceError(E_FAIL) + << "recv error: " << nl_geterror(err); + } } }; @@ -93,9 +130,7 @@ class TNestedAttribute ~TNestedAttribute() { - if (Attribute) { - nla_nest_end(Message, Attribute); - } + nla_nest_end(Message, Attribute); } }; @@ -126,9 +161,12 @@ class TNetlinkMessage ~TNetlinkMessage() { - if (Message) { - nlmsg_free(Message); - } + nlmsg_free(Message); + } + + operator nl_msg*() const + { + return Message; } template @@ -144,17 +182,6 @@ class TNetlinkMessage { return TNestedAttribute(Message, attribute); } - - void Send(nl_sock* socket) - { - // send will free message even if it fails - auto* message = Message; - Message = nullptr; - if (int err = nl_send_sync(socket, message)) { - throw TServiceError(E_FAIL) - << "unable to send message: " << nl_geterror(err); - } - } }; //////////////////////////////////////////////////////////////////////////////// @@ -163,144 +190,155 @@ class TNetlinkDevice final : public IDevice , public std::enable_shared_from_this { -private: - struct THandlerContext - { - std::shared_ptr Device; - - THandlerContext(std::shared_ptr device) - : Device(std::move(device)) - {} - }; - private: const ILoggingServicePtr Logging; const TNetworkAddress ConnectAddress; const TString DeviceName; - const TDuration Timeout; - const TDuration DeadConnectionTimeout; + const TDuration RequestTimeout; + const TDuration ConnectionTimeout; const bool Reconfigure; TLog Log; IClientHandlerPtr Handler; TSocket Socket; ui32 DeviceIndex; - TAtomic ShouldStop = 0; - TPromise StartResult = NewPromise(); - TPromise StopResult = NewPromise(); + TPromise StartResult; + TPromise StopResult; public: TNetlinkDevice( - ILoggingServicePtr logging, - TNetworkAddress connectAddress, - TString deviceName, - TDuration timeout, - TDuration deadConnectionTimeout, - bool reconfigure) - : Logging(std::move(logging)) - , ConnectAddress(std::move(connectAddress)) - , DeviceName(std::move(deviceName)) - , Timeout(timeout) - , DeadConnectionTimeout(deadConnectionTimeout) - , Reconfigure(reconfigure) - { - Log = Logging->CreateLog("BLOCKSTORE_NBD"); - } + ILoggingServicePtr logging, + TNetworkAddress connectAddress, + TString deviceName, + TDuration requestTimeout, + TDuration connectionTimeout, + bool reconfigure); - ~TNetlinkDevice() - { - Stop(false).GetValueSync(); - } + ~TNetlinkDevice(); - TFuture Start() override - { - try { - ParseIndex(); - ConnectSocket(); - ConnectDevice(); - } catch (const TServiceError& e) { - StartResult.SetValue(MakeError( - e.GetCode(), - TStringBuilder() << "unable to configure " << DeviceName - << ": " << e.what())); - } + TFuture Start() override; + TFuture Stop(bool deleteDevice) override; + TFuture Resize(ui64 deviceSizeInBytes) override; + +private: + void ParseIndex(); + + void ConnectSocket(); + void DisconnectSocket(); + + void Connect(); + void Disconnect(); + void DoConnect(bool connected); + + int StatusHandler(genlmsghdr* header); +}; + +//////////////////////////////////////////////////////////////////////////////// + +TNetlinkDevice::TNetlinkDevice( + ILoggingServicePtr logging, + TNetworkAddress connectAddress, + TString deviceName, + TDuration requestTimeout, + TDuration connectionTimeout, + bool reconfigure) + : Logging(std::move(logging)) + , ConnectAddress(std::move(connectAddress)) + , DeviceName(std::move(deviceName)) + , RequestTimeout(requestTimeout) + , ConnectionTimeout(connectionTimeout) + , Reconfigure(reconfigure) +{ + Log = Logging->CreateLog("BLOCKSTORE_NBD"); +} - // will be set asynchronously in Connect > HandleStatus > DoConnect +TNetlinkDevice::~TNetlinkDevice() +{ + Stop(false).GetValueSync(); +} + +TFuture TNetlinkDevice::Start() +{ + if (StartResult.Initialized()) { return StartResult.GetFuture(); } + StartResult = NewPromise(); - TFuture Stop(bool deleteDevice) override - { - if (AtomicSwap(&ShouldStop, 1) == 1) { - return StopResult.GetFuture(); - } + try { + ParseIndex(); + ConnectSocket(); + Connect(); - if (!deleteDevice) { - StopResult.SetValue(MakeError(S_OK)); - return StopResult.GetFuture(); - } + } catch (const TServiceError& e) { + StartResult.SetValue(MakeError( + e.GetCode(), + TStringBuilder() + << "unable to configure " << DeviceName << ": " << e.what())); + } - try { - DisconnectDevice(); - DisconnectSocket(); - StopResult.SetValue(MakeError(S_OK)); - } catch (const TServiceError& e) { - StopResult.SetValue(MakeError( - e.GetCode(), - TStringBuilder() << "unable to disconnect " << DeviceName - << ": " << e.what())); - } + return StartResult.GetFuture(); +} +TFuture TNetlinkDevice::Stop(bool deleteDevice) +{ + if (StopResult.Initialized()) { return StopResult.GetFuture(); } + StopResult = NewPromise(); - NThreading::TFuture Resize(ui64 deviceSizeInBytes) override - { - try { - TNetlinkSocket socket; - TNetlinkMessage message(socket.GetFamily(), NBD_CMD_RECONFIGURE); - - message.Put(NBD_ATTR_INDEX, DeviceIndex); - message.Put(NBD_ATTR_SIZE_BYTES, deviceSizeInBytes); - - { - auto attr = message.Nest(NBD_ATTR_SOCKETS); - auto item = message.Nest(NBD_SOCK_ITEM); - message.Put(NBD_SOCK_FD, static_cast(Socket)); - } + try { + DisconnectSocket(); - message.Send(socket); - } catch (const TServiceError& e) { - return NThreading::MakeFuture(MakeError( - e.GetCode(), - TStringBuilder() - << "unable to resize " << DeviceName << ": " << e.what())); + if (deleteDevice) { + Disconnect(); + } else { + StopResult.SetValue(MakeError(S_OK)); } - return NThreading::MakeFuture(MakeError(S_OK)); + } catch (const TServiceError& e) { + StopResult.SetValue(MakeError( + e.GetCode(), + TStringBuilder() + << "unable to disconnect " << DeviceName << ": " << e.what())); } -private: - void ParseIndex(); + return StopResult.GetFuture(); +} - void ConnectSocket(); - void DisconnectSocket(); +TFuture TNetlinkDevice::Resize(ui64 deviceSizeInBytes) +{ + try { + TNetlinkSocket socket; + TNetlinkMessage message(socket.GetFamily(), NBD_CMD_RECONFIGURE); - void ConnectDevice(); - void DoConnectDevice(bool connected); - void DisconnectDevice(); + message.Put(NBD_ATTR_INDEX, DeviceIndex); + message.Put(NBD_ATTR_SIZE_BYTES, deviceSizeInBytes); - static int StatusHandler(nl_msg* message, void* argument); -}; + { + auto attr = message.Nest(NBD_ATTR_SOCKETS); + auto item = message.Nest(NBD_SOCK_ITEM); + message.Put(NBD_SOCK_FD, static_cast(Socket)); + } -//////////////////////////////////////////////////////////////////////////////// + socket.Send(message); + + } catch (const TServiceError& e) { + return MakeFuture(MakeError( + e.GetCode(), + TStringBuilder() + << "unable to resize " << DeviceName << ": " << e.what())); + } + + return MakeFuture(MakeError(S_OK)); +} void TNetlinkDevice::ParseIndex() { // accept dev/nbd* devices with prefix other than / TStringBuf l, r; TStringBuf(DeviceName).RSplit(NBD_DEVICE_SUFFIX, l, r); + if (!TryFromString(r, DeviceIndex)) { throw TServiceError(E_ARGUMENT) << "unable to parse device index"; } @@ -331,7 +369,34 @@ void TNetlinkDevice::DisconnectSocket() Socket.Close(); } -void TNetlinkDevice::DoConnectDevice(bool connected) +// queries device status eand registers callback that will connect +// or reconfigure (if Reconfigure == true) specified device +void TNetlinkDevice::Connect() +{ + TNetlinkSocket socket; + socket.SetCallback( + NL_CB_VALID, + [device = shared_from_this()] (auto* header) { + return device->StatusHandler(header); + }); + + TNetlinkMessage message(socket.GetFamily(), NBD_CMD_STATUS); + message.Put(NBD_ATTR_INDEX, DeviceIndex); + socket.Send(message); +} + +void TNetlinkDevice::Disconnect() +{ + STORAGE_INFO("disconnect " << DeviceName); + + TNetlinkSocket socket; + TNetlinkMessage message(socket.GetFamily(), NBD_CMD_DISCONNECT); + message.Put(NBD_ATTR_INDEX, DeviceIndex); + socket.Send(message); + StopResult.SetValue(MakeError(S_OK)); +} + +void TNetlinkDevice::DoConnect(bool connected) { try { auto command = NBD_CMD_CONNECT; @@ -356,14 +421,14 @@ void TNetlinkDevice::DoConnectDevice(bool connected) static_cast(info.MinBlockSize)); message.Put(NBD_ATTR_SERVER_FLAGS, static_cast(info.Flags)); - if (Timeout) { - message.Put(NBD_ATTR_TIMEOUT, Timeout.Seconds()); + if (RequestTimeout) { + message.Put(NBD_ATTR_TIMEOUT, RequestTimeout.Seconds()); } - if (DeadConnectionTimeout) { + if (ConnectionTimeout) { message.Put( NBD_ATTR_DEAD_CONN_TIMEOUT, - DeadConnectionTimeout.Seconds()); + ConnectionTimeout.Seconds()); } { @@ -372,7 +437,7 @@ void TNetlinkDevice::DoConnectDevice(bool connected) message.Put(NBD_SOCK_FD, static_cast(Socket)); } - message.Send(socket); + socket.Send(message); StartResult.SetValue(MakeError(S_OK)); } catch (const TServiceError& e) { @@ -383,45 +448,8 @@ void TNetlinkDevice::DoConnectDevice(bool connected) } } -void TNetlinkDevice::DisconnectDevice() -{ - STORAGE_INFO("disconnect " << DeviceName); - - TNetlinkSocket socket; - TNetlinkMessage message(socket.GetFamily(), NBD_CMD_DISCONNECT); - message.Put(NBD_ATTR_INDEX, DeviceIndex); - message.Send(socket); -} - -// queries device status and registers callback that will connect -// or reconfigure (if Reconfigure == true) specified device -void TNetlinkDevice::ConnectDevice() -{ - TNetlinkSocket socket; - auto context = std::make_unique(shared_from_this()); - - if (int err = nl_socket_modify_cb( - socket, - NL_CB_VALID, - NL_CB_CUSTOM, - TNetlinkDevice::StatusHandler, - context.release())) // libnl doesn't throw - { - throw TServiceError(E_FAIL) - << "unable to set socket callback: " << nl_geterror(err); - } - - TNetlinkMessage message(socket.GetFamily(), NBD_CMD_STATUS); - message.Put(NBD_ATTR_INDEX, DeviceIndex); - message.Send(socket); -} - -int TNetlinkDevice::StatusHandler(nl_msg* message, void* argument) +int TNetlinkDevice::StatusHandler(genlmsghdr* header) { - auto* header = static_cast(nlmsg_data(nlmsg_hdr(message))); - auto context = std::unique_ptr( - static_cast(argument)); - nlattr* attr[NBD_ATTR_MAX + 1] = {}; nlattr* deviceItem[NBD_DEVICE_ITEM_MAX + 1] = {}; nlattr* device[NBD_DEVICE_ATTR_MAX + 1] = {}; @@ -440,7 +468,7 @@ int TNetlinkDevice::StatusHandler(nl_msg* message, void* argument) genlmsg_attrlen(header, 0), NULL)) { - context->Device->StartResult.SetValue(MakeError( + StartResult.SetValue(MakeError( E_FAIL, TStringBuilder() << "unable to parse NBD_CMD_STATUS response: " << nl_geterror(err))); @@ -448,7 +476,7 @@ int TNetlinkDevice::StatusHandler(nl_msg* message, void* argument) } if (!attr[NBD_ATTR_DEVICE_LIST]) { - context->Device->StartResult.SetValue(MakeError( + StartResult.SetValue(MakeError( E_FAIL, "did not receive NBD_ATTR_DEVICE_LIST")); return NL_STOP; @@ -460,7 +488,7 @@ int TNetlinkDevice::StatusHandler(nl_msg* message, void* argument) attr[NBD_ATTR_DEVICE_LIST], deviceItemPolicy)) { - context->Device->StartResult.SetValue(MakeError( + StartResult.SetValue(MakeError( E_FAIL, TStringBuilder() << "unable to parse NBD_ATTR_DEVICE_LIST: " << nl_geterror(err))); @@ -468,7 +496,7 @@ int TNetlinkDevice::StatusHandler(nl_msg* message, void* argument) } if (!deviceItem[NBD_DEVICE_ITEM]) { - context->Device->StartResult.SetValue(MakeError( + StartResult.SetValue(MakeError( E_FAIL, "did not receive NBD_DEVICE_ITEM")); return NL_STOP; @@ -480,7 +508,7 @@ int TNetlinkDevice::StatusHandler(nl_msg* message, void* argument) deviceItem[NBD_DEVICE_ITEM], devicePolicy)) { - context->Device->StartResult.SetValue(MakeError( + StartResult.SetValue(MakeError( E_FAIL, TStringBuilder() << "unable to parse NBD_DEVICE_ITEM: " << nl_geterror(err))); @@ -488,14 +516,13 @@ int TNetlinkDevice::StatusHandler(nl_msg* message, void* argument) } if (!device[NBD_DEVICE_CONNECTED]) { - context->Device->StartResult.SetValue(MakeError( + StartResult.SetValue(MakeError( E_FAIL, "did not receive NBD_DEVICE_CONNECTED")); return NL_STOP; } - context->Device->DoConnectDevice(nla_get_u8(device[NBD_DEVICE_CONNECTED])); - + DoConnect(nla_get_u8(device[NBD_DEVICE_CONNECTED])); return NL_OK; } @@ -506,19 +533,19 @@ class TNetlinkDeviceFactory final { private: const ILoggingServicePtr Logging; - const TDuration Timeout; - const TDuration DeadConnectionTimeout; + const TDuration RequestTimeout; + const TDuration ConnectionTimeout; const bool Reconfigure; public: TNetlinkDeviceFactory( ILoggingServicePtr logging, - TDuration timeout, - TDuration deadConnectionTimeout, + TDuration requestTimeout, + TDuration connectionTimeout, bool reconfigure) : Logging(std::move(logging)) - , Timeout(std::move(timeout)) - , DeadConnectionTimeout(std::move(deadConnectionTimeout)) + , RequestTimeout(requestTimeout) + , ConnectionTimeout(connectionTimeout) , Reconfigure(reconfigure) {} @@ -535,8 +562,8 @@ class TNetlinkDeviceFactory final Logging, connectAddress, std::move(deviceName), - Timeout, - DeadConnectionTimeout, + RequestTimeout, + ConnectionTimeout, Reconfigure); } }; @@ -549,29 +576,29 @@ IDevicePtr CreateNetlinkDevice( ILoggingServicePtr logging, TNetworkAddress connectAddress, TString deviceName, - TDuration timeout, - TDuration deadConnectionTimeout, + TDuration requestTimeout, + TDuration connectionTimeout, bool reconfigure) { return std::make_shared( std::move(logging), std::move(connectAddress), std::move(deviceName), - timeout, - deadConnectionTimeout, + requestTimeout, + connectionTimeout, reconfigure); } IDeviceFactoryPtr CreateNetlinkDeviceFactory( ILoggingServicePtr logging, - TDuration timeout, - TDuration deadConnectionTimeout, + TDuration requestTimeout, + TDuration connectionTimeout, bool reconfigure) { return std::make_shared( std::move(logging), - std::move(timeout), - std::move(deadConnectionTimeout), + requestTimeout, + connectionTimeout, reconfigure); } diff --git a/cloud/blockstore/libs/nbd/netlink_device.h b/cloud/blockstore/libs/nbd/netlink_device.h index 1e60d6e0259..97e3938010f 100644 --- a/cloud/blockstore/libs/nbd/netlink_device.h +++ b/cloud/blockstore/libs/nbd/netlink_device.h @@ -10,14 +10,14 @@ IDevicePtr CreateNetlinkDevice( ILoggingServicePtr logging, TNetworkAddress connectAddress, TString deviceName, - TDuration timeout, - TDuration deadConnectionTimeout, + TDuration requestTimeout, + TDuration connectionTimeout, bool reconfigure); IDeviceFactoryPtr CreateNetlinkDeviceFactory( ILoggingServicePtr logging, - TDuration timeout, - TDuration deadConnectionTimeout, + TDuration requestTimeout, + TDuration connectionTimeout, bool reconfigure); } // namespace NCloud::NBlockStore::NBD diff --git a/cloud/blockstore/tools/nbd/bootstrap.cpp b/cloud/blockstore/tools/nbd/bootstrap.cpp index 9ce09227d57..919d8d319a1 100644 --- a/cloud/blockstore/tools/nbd/bootstrap.cpp +++ b/cloud/blockstore/tools/nbd/bootstrap.cpp @@ -297,17 +297,22 @@ void TBootstrap::Start() Logging, listenAddress, Options->ConnectDevice, - Options->Timeout, - Options->DeadConnectionTimeout, + Options->RequestTimeout, + Options->ConnectionTimeout, Options->Reconfigure); } else { + // The only case we want kernel to retry requests is when the socket + // is dead due to nbd server restart. And since we can't configure + // ioctl device to use a new socket, request timeout effectively + // becomes connection timeout NbdDevice = CreateDevice( Logging, listenAddress, Options->ConnectDevice, - Options->Timeout); + Options->ConnectionTimeout); } - auto status = NbdDevice->Start().ExtractValue(); + auto future = NbdDevice->Start(); + const auto& status = future.GetValue(); if (HasError(status)) { ythrow yexception() << status.GetMessage(); } diff --git a/cloud/blockstore/tools/nbd/options.cpp b/cloud/blockstore/tools/nbd/options.cpp index 01cc63da536..9cd9f5ab594 100644 --- a/cloud/blockstore/tools/nbd/options.cpp +++ b/cloud/blockstore/tools/nbd/options.cpp @@ -192,23 +192,23 @@ void TOptions::Parse(int argc, char** argv) .RequiredArgument("NUM") .StoreResult(&MaxInFlightBytes); - opts.AddLongOption("timeout", "request timeout") + opts.AddLongOption("request-timeout", "request timeout") .OptionalArgument("NUM") .Handler1T([this] (const auto& s) { - Timeout = TDuration::Parse(s); + RequestTimeout = TDuration::Parse(s); Y_ENSURE( - Timeout.MicroSeconds() % 1000000 == 0, + RequestTimeout.MicroSeconds() % 1000000 == 0, "timeout should be a multiple of a second" ); }); - opts.AddLongOption("dead-connection-timeout", "dead connection timeout") + opts.AddLongOption("connection-timeout", "connection timeout") .OptionalArgument("NUM") .Handler1T([this] (const auto& s) { - DeadConnectionTimeout = TDuration::Parse(s); + ConnectionTimeout = TDuration::Parse(s); Y_ENSURE( - DeadConnectionTimeout.MicroSeconds() % 1000000 == 0, - "dead connection timeout should be a multiple of a second" + ConnectionTimeout.MicroSeconds() % 1000000 == 0, + "connection timeout should be a multiple of a second" ); }); diff --git a/cloud/blockstore/tools/nbd/options.h b/cloud/blockstore/tools/nbd/options.h index df10bdc79b7..1e1b853b56d 100644 --- a/cloud/blockstore/tools/nbd/options.h +++ b/cloud/blockstore/tools/nbd/options.h @@ -70,8 +70,8 @@ struct TOptions bool UnalignedRequestsDisabled = false; - TDuration Timeout = TDuration::Days(1); - TDuration DeadConnectionTimeout = TDuration::Hours(1); + TDuration RequestTimeout = TDuration::Minutes(5); + TDuration ConnectionTimeout = TDuration::Hours(1); void Parse(int argc, char** argv); };