2017-05-26 04:48:44 +08:00
|
|
|
/*
|
|
|
|
* Net2.actor.cpp
|
|
|
|
*
|
|
|
|
* This source file is part of the FoundationDB open source project
|
|
|
|
*
|
2022-03-22 04:36:23 +08:00
|
|
|
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2018-02-22 02:25:11 +08:00
|
|
|
*
|
2017-05-26 04:48:44 +08:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2020-08-07 04:06:50 +08:00
|
|
|
#include "boost/asio/buffer.hpp"
|
|
|
|
#include "boost/asio/ip/address.hpp"
|
|
|
|
#include "boost/system/system_error.hpp"
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "flow/Platform.h"
|
2020-08-07 04:06:50 +08:00
|
|
|
#include "flow/Trace.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
#include <algorithm>
|
2020-08-07 04:06:50 +08:00
|
|
|
#include <memory>
|
2017-05-26 04:48:44 +08:00
|
|
|
#define BOOST_SYSTEM_NO_LIB
|
|
|
|
#define BOOST_DATE_TIME_NO_LIB
|
|
|
|
#define BOOST_REGEX_NO_LIB
|
2020-04-19 11:21:10 +08:00
|
|
|
#include <boost/asio.hpp>
|
|
|
|
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
|
|
|
#include <boost/range.hpp>
|
|
|
|
#include <boost/algorithm/string/join.hpp>
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "flow/network.h"
|
|
|
|
#include "flow/IThreadPool.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2018-10-20 01:30:13 +08:00
|
|
|
#include "flow/ActorCollection.h"
|
|
|
|
#include "flow/ThreadSafeQueue.h"
|
|
|
|
#include "flow/ThreadHelper.actor.h"
|
|
|
|
#include "flow/TDMetric.actor.h"
|
|
|
|
#include "flow/AsioReactor.h"
|
2017-10-12 05:13:16 +08:00
|
|
|
#include "flow/Profiler.h"
|
2019-06-19 05:49:04 +08:00
|
|
|
#include "flow/ProtocolVersion.h"
|
2020-12-27 04:30:00 +08:00
|
|
|
#include "flow/SendBufferIterator.h"
|
2020-03-05 12:14:47 +08:00
|
|
|
#include "flow/TLSConfig.actor.h"
|
2020-03-06 09:25:33 +08:00
|
|
|
#include "flow/genericactors.actor.h"
|
2020-06-23 14:45:47 +08:00
|
|
|
#include "flow/Util.h"
|
2020-03-06 09:25:33 +08:00
|
|
|
|
2021-03-11 05:24:55 +08:00
|
|
|
#ifdef ADDRESS_SANITIZER
|
|
|
|
#include <sanitizer/lsan_interface.h>
|
|
|
|
#endif
|
|
|
|
|
2020-03-06 09:25:33 +08:00
|
|
|
// See the comment in TLSConfig.actor.h for the explanation of why this module breaking include was done.
|
|
|
|
#include "fdbrpc/IAsyncFile.h"
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <mmsystem.h>
|
|
|
|
#endif
|
2021-03-11 02:06:03 +08:00
|
|
|
#include "flow/actorcompiler.h" // This must be the last #include.
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// Defined to track the stack limit
|
|
|
|
extern "C" intptr_t g_stackYieldLimit;
|
|
|
|
intptr_t g_stackYieldLimit = 0;
|
|
|
|
|
|
|
|
using namespace boost::asio::ip;
|
|
|
|
|
2020-02-02 05:23:53 +08:00
|
|
|
#if defined(__linux__) || defined(__FreeBSD__)
|
2017-05-26 04:48:44 +08:00
|
|
|
#include <execinfo.h>
|
|
|
|
|
2020-01-29 04:09:37 +08:00
|
|
|
std::atomic<int64_t> net2RunLoopIterations(0);
|
|
|
|
std::atomic<int64_t> net2RunLoopSleeps(0);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
volatile size_t net2backtraces_max = 10000;
|
2020-08-28 06:31:24 +08:00
|
|
|
volatile void** volatile net2backtraces = nullptr;
|
2017-05-26 04:48:44 +08:00
|
|
|
volatile size_t net2backtraces_offset = 0;
|
|
|
|
volatile bool net2backtraces_overflow = false;
|
|
|
|
volatile int net2backtraces_count = 0;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
volatile void** other_backtraces = nullptr;
|
2017-05-26 04:48:44 +08:00
|
|
|
sigset_t sigprof_set;
|
|
|
|
|
|
|
|
void initProfiling() {
|
|
|
|
net2backtraces = new volatile void*[net2backtraces_max];
|
|
|
|
other_backtraces = new volatile void*[net2backtraces_max];
|
|
|
|
|
|
|
|
// According to folk wisdom, calling this once before setting up the signal handler makes
|
|
|
|
// it async signal safe in practice :-/
|
|
|
|
backtrace(const_cast<void**>(other_backtraces), net2backtraces_max);
|
|
|
|
|
|
|
|
sigemptyset(&sigprof_set);
|
|
|
|
sigaddset(&sigprof_set, SIGPROF);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
DESCR struct SlowTask {
|
2021-03-11 02:06:03 +08:00
|
|
|
int64_t clocks; // clocks
|
2017-05-26 04:48:44 +08:00
|
|
|
int64_t duration; // ns
|
|
|
|
int64_t priority; // priority level
|
|
|
|
int64_t numYields; // count
|
|
|
|
};
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
namespace N2 { // No indent, it's the whole file
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
class Net2;
|
|
|
|
class Peer;
|
|
|
|
class Connection;
|
|
|
|
|
2021-01-22 06:22:03 +08:00
|
|
|
// Outlives main
|
2021-03-11 02:06:03 +08:00
|
|
|
Net2* g_net2 = nullptr;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
class Task {
|
|
|
|
public:
|
|
|
|
virtual void operator()() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct OrderedTask {
|
|
|
|
int64_t priority;
|
2019-06-25 17:47:35 +08:00
|
|
|
TaskPriority taskID;
|
2021-03-11 02:06:03 +08:00
|
|
|
Task* task;
|
2019-06-25 17:47:35 +08:00
|
|
|
OrderedTask(int64_t priority, TaskPriority taskID, Task* task) : priority(priority), taskID(taskID), task(task) {}
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator<(OrderedTask const& rhs) const { return priority < rhs.priority; }
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
2021-01-20 09:13:27 +08:00
|
|
|
template <class T>
|
2021-03-11 02:06:03 +08:00
|
|
|
class ReadyQueue : public std::priority_queue<T, std::vector<T>> {
|
2021-01-20 09:13:27 +08:00
|
|
|
public:
|
|
|
|
typedef typename std::priority_queue<T, std::vector<T>>::size_type size_type;
|
|
|
|
ReadyQueue(size_type capacity = 0) { reserve(capacity); };
|
2021-03-11 02:06:03 +08:00
|
|
|
void reserve(size_type capacity) { this->c.reserve(capacity); }
|
2021-01-20 09:13:27 +08:00
|
|
|
};
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
thread_local INetwork* thread_network = 0;
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
class Net2 final : public INetwork, public INetworkConnections {
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-16 07:23:56 +08:00
|
|
|
private:
|
2021-03-24 04:56:37 +08:00
|
|
|
void updateStarvationTracker(struct NetworkMetrics::PriorityStats& binStats,
|
2021-03-24 07:09:08 +08:00
|
|
|
TaskPriority priority,
|
|
|
|
TaskPriority lastPriority,
|
|
|
|
double now);
|
2021-03-17 05:49:36 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
2020-03-05 12:14:47 +08:00
|
|
|
Net2(const TLSConfig& tlsConfig, bool useThreadPool, bool useMetrics);
|
2021-01-26 09:55:43 +08:00
|
|
|
void initTLS(ETLSInitState targetState) override;
|
|
|
|
void run() override;
|
|
|
|
void initMetrics() override;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// INetworkConnections interface
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Reference<IConnection>> connect(NetworkAddress toAddr, const std::string& host) override;
|
|
|
|
Future<Reference<IConnection>> connectExternal(NetworkAddress toAddr, const std::string& host) override;
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Reference<IUDPSocket>> createUDPSocket(NetworkAddress toAddr) override;
|
|
|
|
Future<Reference<IUDPSocket>> createUDPSocket(bool isV6) override;
|
2022-01-15 04:02:21 +08:00
|
|
|
// The mock DNS methods should only be used in simulation.
|
2021-11-16 06:34:52 +08:00
|
|
|
void addMockTCPEndpoint(const std::string& host,
|
|
|
|
const std::string& service,
|
|
|
|
const std::vector<NetworkAddress>& addresses) override {
|
|
|
|
throw operation_failed();
|
|
|
|
}
|
2022-01-15 04:02:21 +08:00
|
|
|
// The mock DNS methods should only be used in simulation.
|
|
|
|
void removeMockTCPEndpoint(const std::string& host, const std::string& service) override {
|
|
|
|
throw operation_failed();
|
|
|
|
}
|
2022-01-15 11:02:35 +08:00
|
|
|
void parseMockDNSFromString(const std::string& s) override { throw operation_failed(); }
|
|
|
|
std::string convertMockDNSToString() override { throw operation_failed(); }
|
2022-01-15 04:02:21 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<std::vector<NetworkAddress>> resolveTCPEndpoint(const std::string& host,
|
|
|
|
const std::string& service) override;
|
2022-04-04 08:33:18 +08:00
|
|
|
Future<std::vector<NetworkAddress>> resolveTCPEndpointWithDNSCache(const std::string& host,
|
|
|
|
const std::string& service) override;
|
2022-01-28 06:25:50 +08:00
|
|
|
std::vector<NetworkAddress> resolveTCPEndpointBlocking(const std::string& host,
|
|
|
|
const std::string& service) override;
|
2022-04-04 08:33:18 +08:00
|
|
|
std::vector<NetworkAddress> resolveTCPEndpointBlockingWithDNSCache(const std::string& host,
|
|
|
|
const std::string& service) override;
|
2021-03-11 02:06:03 +08:00
|
|
|
Reference<IListener> listen(NetworkAddress localAddr) override;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// INetwork interface
|
2020-11-23 12:09:10 +08:00
|
|
|
double now() const override { return currentTime; };
|
|
|
|
double timer() override { return ::timer(); };
|
2020-11-06 01:03:26 +08:00
|
|
|
double timer_monotonic() override { return ::timer_monotonic(); };
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Void> delay(double seconds, TaskPriority taskId) override;
|
2021-07-28 03:01:32 +08:00
|
|
|
Future<Void> orderedDelay(double seconds, TaskPriority taskId) override;
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<class Void> yield(TaskPriority taskID) override;
|
|
|
|
bool check_yield(TaskPriority taskId) override;
|
|
|
|
TaskPriority getCurrentTask() const override { return currentTaskID; }
|
2021-03-11 02:06:03 +08:00
|
|
|
void setCurrentTask(TaskPriority taskID) override {
|
|
|
|
currentTaskID = taskID;
|
|
|
|
priorityMetric = (int64_t)taskID;
|
2019-06-11 08:12:04 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
void onMainThread(Promise<Void>&& signal, TaskPriority taskID) override;
|
|
|
|
bool isOnMainThread() const override { return thread_network == this; }
|
2020-11-23 12:09:10 +08:00
|
|
|
void stop() override {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (thread_network == this)
|
2017-05-26 04:48:44 +08:00
|
|
|
stopImmediately();
|
|
|
|
else
|
2021-03-11 02:06:03 +08:00
|
|
|
onMainThreadVoid([this] { this->stopImmediately(); }, nullptr);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
void addStopCallback(std::function<void()> fn) override {
|
|
|
|
if (thread_network == this)
|
2020-04-20 17:53:07 +08:00
|
|
|
stopCallbacks.emplace_back(std::move(fn));
|
|
|
|
else
|
2021-03-11 02:06:03 +08:00
|
|
|
onMainThreadVoid([this, fn] { this->stopCallbacks.emplace_back(std::move(fn)); }, nullptr);
|
2020-04-20 17:53:07 +08:00
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
bool isSimulated() const override { return false; }
|
2021-07-09 06:51:01 +08:00
|
|
|
THREAD_HANDLE startThread(THREAD_FUNC_RETURN (*func)(void*), void* arg, int stackSize, const char* name) override;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void getDiskBytes(std::string const& directory, int64_t& free, int64_t& total) override;
|
2020-11-23 12:09:10 +08:00
|
|
|
bool isAddressOnThisHost(NetworkAddress const& addr) const override;
|
2021-03-11 02:06:03 +08:00
|
|
|
void updateNow() { currentTime = timer_monotonic(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
flowGlobalType global(int id) const override { return (globals.size() > id) ? globals[id] : nullptr; }
|
2021-03-11 02:06:03 +08:00
|
|
|
void setGlobal(size_t id, flowGlobalType v) override {
|
2021-11-18 07:25:36 +08:00
|
|
|
ASSERT(id < globals.size());
|
2021-03-11 02:06:03 +08:00
|
|
|
globals[id] = v;
|
|
|
|
}
|
2020-09-29 01:58:49 +08:00
|
|
|
|
2021-10-20 08:37:03 +08:00
|
|
|
ProtocolVersion protocolVersion() const override { return currentProtocolVersion; }
|
2020-09-29 01:58:49 +08:00
|
|
|
|
2020-12-27 08:47:00 +08:00
|
|
|
std::vector<flowGlobalType> globals;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
const TLSConfig& getTLSConfig() const override { return tlsConfig; }
|
2020-03-13 15:11:53 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
bool checkRunnable() override;
|
2020-05-23 04:31:06 +08:00
|
|
|
|
2021-07-24 08:18:13 +08:00
|
|
|
#ifdef ENABLE_SAMPLING
|
2021-06-04 06:10:04 +08:00
|
|
|
ActorLineageSet& getActorLineageSet() override;
|
2021-07-24 08:18:13 +08:00
|
|
|
#endif
|
2021-06-04 06:10:04 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
bool useThreadPool;
|
2020-06-21 21:17:55 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// private:
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
ASIOReactor reactor;
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
2020-03-06 09:25:33 +08:00
|
|
|
AsyncVar<Reference<ReferencedObject<boost::asio::ssl::context>>> sslContextVar;
|
2020-06-23 18:09:56 +08:00
|
|
|
Reference<IThreadPool> sslHandshakerPool;
|
2020-06-29 08:29:13 +08:00
|
|
|
int sslHandshakerThreadsStarted;
|
2020-06-23 18:09:56 +08:00
|
|
|
int sslPoolHandshakesInProgress;
|
2020-02-20 10:37:47 +08:00
|
|
|
#endif
|
2020-03-05 12:14:47 +08:00
|
|
|
TLSConfig tlsConfig;
|
2020-03-06 09:25:33 +08:00
|
|
|
Future<Void> backgroundCertRefresh;
|
2020-06-29 08:29:13 +08:00
|
|
|
ETLSInitState tlsInitializedState;
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
INetworkConnections* network; // initially this, but can be changed
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-02-08 02:35:09 +08:00
|
|
|
int64_t tscBegin, tscEnd;
|
2017-05-26 04:48:44 +08:00
|
|
|
double taskBegin;
|
2019-06-25 17:47:35 +08:00
|
|
|
TaskPriority currentTaskID;
|
2017-05-26 04:48:44 +08:00
|
|
|
uint64_t tasksIssued;
|
|
|
|
TDMetricCollection tdmetrics;
|
2021-07-29 07:03:37 +08:00
|
|
|
ChaosMetrics chaosMetrics;
|
2021-06-04 06:10:04 +08:00
|
|
|
// we read now() from a different thread. On Intel, reading a double is atomic anyways, but on other platforms it's
|
|
|
|
// not. For portability this should be atomic
|
|
|
|
std::atomic<double> currentTime;
|
2021-03-19 07:31:29 +08:00
|
|
|
// May be accessed off the network thread, e.g. by onMainThread
|
Fix a data race
TSAN output:
3: WARNING: ThreadSanitizer: data race (pid=63)
3: Read of size 1 at 0x7b6800000970 by thread T1:
3: #0 N2::Net2::onMainThread(Promise<Void>&&, TaskPriority) /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1734:6 (libfdb_c.so+0xca3d9e)
3: #1 void onMainThreadVoid<ThreadSingleAssignmentVarBase::cancel()::'lambda'()>(ThreadSingleAssignmentVarBase::cancel()::'lambda'(), Error*, TaskPriority) /home/anoyes/workspace/foundationdb/flow/ThreadHelper.actor.h:47:13 (libfdb_c.so+0x3fe73a)
3: #2 ThreadSingleAssignmentVarBase::cancel() /home/anoyes/workspace/foundationdb/flow/ThreadHelper.actor.h:317:3 (libfdb_c.so+0x3fe290)
3: #3 fdb_future_cancel /home/anoyes/workspace/foundationdb/bindings/c/fdb_c.cpp:141:96 (libfdb_c.so+0x3f7896)
3: #4 DLThreadSingleAssignmentVar<long>::cancel() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionAssignmentVars.h:175:4 (libfdb_c.so+0x45bd4d)
3: #5 MapSingleAssignmentVar<long, Void>::cancel() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionAssignmentVars.h:241:20 (libfdb_c.so+0x475ba7)
3: #6 FlatMapSingleAssignmentVar<Void, Void>::cancel() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionAssignmentVars.h:301:27 (libfdb_c.so+0x4742ce)
3: #7 ThreadFuture<Void>::cancel() /home/anoyes/workspace/foundationdb/flow/ThreadHelper.actor.h:444:32 (libfdb_c.so+0x441237)
3: #8 MultiVersionDatabase::Connector::cancel() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:969:20 (libfdb_c.so+0x441237)
3: #9 MultiVersionDatabase::DatabaseState::cancelConnections()::$_22::operator()() const /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1082:11 (libfdb_c.so+0x441237)
3: #10 (anonymous namespace)::DoOnMainThreadVoidActorState<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22, (anonymous namespace)::DoOnMainThreadVoidActor<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22> >::a_body1cont1(Void const&, int) /home/anoyes/workspace/foundationdb/flow/ThreadHelper.actor.h:559:2 (libfdb_c.so+0x441237)
3: #11 (anonymous namespace)::DoOnMainThreadVoidActorState<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22, (anonymous namespace)::DoOnMainThreadVoidActor<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22> >::a_body1when1(Void const&, int) /home/anoyes/build/foundationdb-tsan/flow/ThreadHelper.actor.g.h:992:15 (libfdb_c.so+0x441237)
3: #12 (anonymous namespace)::DoOnMainThreadVoidActorState<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22, (anonymous namespace)::DoOnMainThreadVoidActor<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22> >::a_callback_fire(ActorCallback<(anonymous namespace)::DoOnMainThreadVoidActor<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22>, 0, Void>*, Void const&) /home/anoyes/build/foundationdb-tsan/flow/ThreadHelper.actor.g.h:1013:4 (libfdb_c.so+0x440dff)
3: #13 ActorCallback<(anonymous namespace)::DoOnMainThreadVoidActor<MultiVersionDatabase::DatabaseState::cancelConnections()::$_22>, 0, Void>::fire(Void const&) /home/anoyes/workspace/foundationdb/flow/flow.h:1016:78 (libfdb_c.so+0x440dff)
3: #14 void SAV<Void>::send<Void>(Void&&) /home/anoyes/workspace/foundationdb/flow/flow.h:465:23 (libfdb_c.so+0x4086b2)
3: #15 void Promise<Void>::send<Void>(Void&&) const /home/anoyes/workspace/foundationdb/flow/flow.h:782:8 (libfdb_c.so+0xcc079e)
3: #16 N2::PromiseTask::operator()() /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1157:11 (libfdb_c.so+0xcc079e)
3: #17 N2::Net2::run() /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1493:5 (libfdb_c.so+0xca1640)
3: #18 runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/NativeAPI.actor.cpp:1774:13 (libfdb_c.so+0x499eb4)
3: #19 ThreadSafeApi::runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/ThreadSafeTransaction.cpp:429:3 (libfdb_c.so+0xb666cc)
3: #20 MultiVersionApi::runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1521:20 (libfdb_c.so+0x41e9dd)
3: #21 fdb_run_network /home/anoyes/workspace/foundationdb/bindings/c/fdb_c.cpp:129:45 (libfdb_c.so+0x3f7645)
3: #22 decltype(std::__1::forward<int (*)()>(fp)()) std::__1::__invoke<int (*)()>(int (*&&)()) /usr/local/bin/../include/c++/v1/type_traits:3539:173 (fdb_c_unit_tests+0x384856)
3: #23 void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, int (*)()>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, int (*)()>&, std::__1::__tuple_indices<>) /usr/local/bin/../include/c++/v1/thread:273:5 (fdb_c_unit_tests+0x384856)
3: #24 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, int (*)()> >(void*) /usr/local/bin/../include/c++/v1/thread:284:5 (fdb_c_unit_tests+0x384856)
3:
3: Previous write of size 1 at 0x7b6800000970 by thread T2:
3: #0 N2::Net2::stopImmediately() /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:253:11 (libfdb_c.so+0xca936b)
3: #1 N2::Net2::stop()::'lambda'()::operator()() const /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:171:36 (libfdb_c.so+0xca936b)
3: #2 (anonymous namespace)::DoOnMainThreadVoidActorState<N2::Net2::stop()::'lambda'(), (anonymous namespace)::DoOnMainThreadVoidActor<N2::Net2::stop()::'lambda'()> >::a_body1cont1(Void const&, int) /home/anoyes/workspace/foundationdb/flow/ThreadHelper.actor.h:559:2 (libfdb_c.so+0xca936b)
3: #3 (anonymous namespace)::DoOnMainThreadVoidActorState<N2::Net2::stop()::'lambda'(), (anonymous namespace)::DoOnMainThreadVoidActor<N2::Net2::stop()::'lambda'()> >::a_body1when1(Void const&, int) /home/anoyes/build/foundationdb-tsan/flow/ThreadHelper.actor.g.h:992:15 (libfdb_c.so+0xca936b)
3: #4 (anonymous namespace)::DoOnMainThreadVoidActorState<N2::Net2::stop()::'lambda'(), (anonymous namespace)::DoOnMainThreadVoidActor<N2::Net2::stop()::'lambda'()> >::a_callback_fire(ActorCallback<(anonymous namespace)::DoOnMainThreadVoidActor<N2::Net2::stop()::'lambda'()>, 0, Void>*, Void const&) /home/anoyes/build/foundationdb-tsan/flow/ThreadHelper.actor.g.h:1013:4 (libfdb_c.so+0xca9128)
3: #5 ActorCallback<(anonymous namespace)::DoOnMainThreadVoidActor<N2::Net2::stop()::'lambda'()>, 0, Void>::fire(Void const&) /home/anoyes/workspace/foundationdb/flow/flow.h:1016:78 (libfdb_c.so+0xca9128)
3: #6 void SAV<Void>::send<Void>(Void&&) /home/anoyes/workspace/foundationdb/flow/flow.h:465:23 (libfdb_c.so+0x4086b2)
3: #7 void Promise<Void>::send<Void>(Void&&) const /home/anoyes/workspace/foundationdb/flow/flow.h:782:8 (libfdb_c.so+0xcc079e)
3: #8 N2::PromiseTask::operator()() /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1157:11 (libfdb_c.so+0xcc079e)
3: #9 N2::Net2::run() /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1493:5 (libfdb_c.so+0xca1640)
3: #10 runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/NativeAPI.actor.cpp:1774:13 (libfdb_c.so+0x499eb4)
3: #11 ThreadSafeApi::runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/ThreadSafeTransaction.cpp:429:3 (libfdb_c.so+0xb666cc)
3: #12 MultiVersionApi::runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1521:20 (libfdb_c.so+0x41e9dd)
3: #13 fdb_run_network /home/anoyes/workspace/foundationdb/bindings/c/fdb_c.cpp:129:45 (libfdb_c.so+0x3f7645)
3: #14 DLApi::runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:492:11 (libfdb_c.so+0x40dd18)
3: #15 runNetworkThread(void*) /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1495:30 (libfdb_c.so+0x41e895)
3:
3: Location is heap block of size 1304 at 0x7b6800000600 allocated by main thread:
3: #0 operator new(unsigned long) <null> (fdb_c_unit_tests+0x31694e)
3: #1 newNet2(TLSConfig const&, bool, bool) /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1969:16 (libfdb_c.so+0xca607d)
3: #2 setupNetwork(unsigned long, bool) /home/anoyes/workspace/foundationdb/fdbclient/NativeAPI.actor.cpp:1754:14 (libfdb_c.so+0x499c53)
3: #3 ThreadSafeApi::setupNetwork() /home/anoyes/workspace/foundationdb/fdbclient/ThreadSafeTransaction.cpp:423:2 (libfdb_c.so+0xb66675)
3: #4 MultiVersionApi::setupNetwork() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1462:21 (libfdb_c.so+0x41dc42)
3: #5 fdb_setup_network_impl() /home/anoyes/workspace/foundationdb/bindings/c/fdb_c.cpp:116:45 (libfdb_c.so+0x3f7525)
3: #6 DLApi::setupNetwork() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:488:15 (libfdb_c.so+0x40dc88)
3: #7 MultiVersionApi::setupNetwork()::$_27::operator()(Reference<ClientInfo>) const /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1481:17 (libfdb_c.so+0x442cd4)
3: #8 decltype(std::__1::forward<MultiVersionApi::setupNetwork()::$_27&>(fp)(std::__1::forward<Reference<ClientInfo> >(fp0))) std::__1::__invoke<MultiVersionApi::setupNetwork()::$_27&, Reference<ClientInfo> >(MultiVersionApi::setupNetwork()::$_27&, Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/type_traits:3539:173 (libfdb_c.so+0x442cd4)
3: #9 void std::__1::__invoke_void_return_wrapper<void>::__call<MultiVersionApi::setupNetwork()::$_27&, Reference<ClientInfo> >(MultiVersionApi::setupNetwork()::$_27&, Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/__functional_base:348:9 (libfdb_c.so+0x442cd4)
3: #10 std::__1::__function::__alloc_func<MultiVersionApi::setupNetwork()::$_27, std::__1::allocator<MultiVersionApi::setupNetwork()::$_27>, void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/functional:1540:16 (libfdb_c.so+0x442cd4)
3: #11 std::__1::__function::__func<MultiVersionApi::setupNetwork()::$_27, std::__1::allocator<MultiVersionApi::setupNetwork()::$_27>, void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/functional:1714:12 (libfdb_c.so+0x442cd4)
3: #12 std::__1::__function::__value_func<void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>&&) const /usr/local/bin/../include/c++/v1/functional:1867:16 (libfdb_c.so+0x4153ed)
3: #13 std::__1::function<void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>) const /usr/local/bin/../include/c++/v1/functional:2473:12 (libfdb_c.so+0x4153ed)
3: #14 MultiVersionApi::runOnExternalClients(int, std::__1::function<void (Reference<ClientInfo>)>, bool) /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1117:5 (libfdb_c.so+0x4153ed)
3: #15 MultiVersionApi::runOnExternalClientsAllThreads(std::__1::function<void (Reference<ClientInfo>)>, bool) /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1102:3 (libfdb_c.so+0x41992c)
3: #16 MultiVersionApi::setupNetwork() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1475:3 (libfdb_c.so+0x41dd2a)
3: #17 fdb_setup_network_impl() /home/anoyes/workspace/foundationdb/bindings/c/fdb_c.cpp:116:45 (libfdb_c.so+0x3f7525)
3: #18 main /home/anoyes/workspace/foundationdb/bindings/c/test/unit/unit_tests.cpp:2147:12 (fdb_c_unit_tests+0x35f6b2)
3:
3: Thread T1 (tid=65, running) created by main thread at:
3: #0 pthread_create <null> (fdb_c_unit_tests+0x29df32)
3: #1 std::__1::__libcpp_thread_create(unsigned long*, void* (*)(void*), void*) /usr/local/bin/../include/c++/v1/__threading_support:394:10 (fdb_c_unit_tests+0x372da6)
3: #2 std::__1::thread::thread<int (*)(), void>(int (*&&)()) /usr/local/bin/../include/c++/v1/thread:300:16 (fdb_c_unit_tests+0x372da6)
3: #3 main /home/anoyes/workspace/foundationdb/bindings/c/test/unit/unit_tests.cpp:2148:14 (fdb_c_unit_tests+0x35f6dd)
3:
3: Thread T2 (tid=66, finished) created by thread T1 at:
3: #0 pthread_create <null> (fdb_c_unit_tests+0x29df32)
3: #1 startThread(void* (*)(void*), void*, int, char const*) /home/anoyes/workspace/foundationdb/flow/Platform.actor.cpp:2745:2 (libfdb_c.so+0xd08d74)
3: #2 N2::Net2::startThread(void* (*)(void*), void*) /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1749:9 (libfdb_c.so+0xca42a4)
3: #3 MultiVersionApi::runNetwork()::$_28::operator()(Reference<ClientInfo>) const /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1516:34 (libfdb_c.so+0x443106)
3: #4 decltype(std::__1::forward<MultiVersionApi::runNetwork()::$_28&>(fp)(std::__1::forward<Reference<ClientInfo> >(fp0))) std::__1::__invoke<MultiVersionApi::runNetwork()::$_28&, Reference<ClientInfo> >(MultiVersionApi::runNetwork()::$_28&, Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/type_traits:3539:173 (libfdb_c.so+0x443106)
3: #5 void std::__1::__invoke_void_return_wrapper<void>::__call<MultiVersionApi::runNetwork()::$_28&, Reference<ClientInfo> >(MultiVersionApi::runNetwork()::$_28&, Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/__functional_base:348:9 (libfdb_c.so+0x443106)
3: #6 std::__1::__function::__alloc_func<MultiVersionApi::runNetwork()::$_28, std::__1::allocator<MultiVersionApi::runNetwork()::$_28>, void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/functional:1540:16 (libfdb_c.so+0x443106)
3: #7 std::__1::__function::__func<MultiVersionApi::runNetwork()::$_28, std::__1::allocator<MultiVersionApi::runNetwork()::$_28>, void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>&&) /usr/local/bin/../include/c++/v1/functional:1714:12 (libfdb_c.so+0x443106)
3: #8 std::__1::__function::__value_func<void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>&&) const /usr/local/bin/../include/c++/v1/functional:1867:16 (libfdb_c.so+0x4153ed)
3: #9 std::__1::function<void (Reference<ClientInfo>)>::operator()(Reference<ClientInfo>) const /usr/local/bin/../include/c++/v1/functional:2473:12 (libfdb_c.so+0x4153ed)
3: #10 MultiVersionApi::runOnExternalClients(int, std::__1::function<void (Reference<ClientInfo>)>, bool) /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1117:5 (libfdb_c.so+0x4153ed)
3: #11 MultiVersionApi::runOnExternalClientsAllThreads(std::__1::function<void (Reference<ClientInfo>)>, bool) /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1102:3 (libfdb_c.so+0x41992c)
3: #12 MultiVersionApi::runNetwork() /home/anoyes/workspace/foundationdb/fdbclient/MultiVersionTransaction.actor.cpp:1514:3 (libfdb_c.so+0x41ea53)
3: #13 fdb_run_network /home/anoyes/workspace/foundationdb/bindings/c/fdb_c.cpp:129:45 (libfdb_c.so+0x3f7645)
3: #14 decltype(std::__1::forward<int (*)()>(fp)()) std::__1::__invoke<int (*)()>(int (*&&)()) /usr/local/bin/../include/c++/v1/type_traits:3539:173 (fdb_c_unit_tests+0x384856)
3: #15 void std::__1::__thread_execute<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, int (*)()>(std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, int (*)()>&, std::__1::__tuple_indices<>) /usr/local/bin/../include/c++/v1/thread:273:5 (fdb_c_unit_tests+0x384856)
3: #16 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, int (*)()> >(void*) /usr/local/bin/../include/c++/v1/thread:284:5 (fdb_c_unit_tests+0x384856)
3:
3: SUMMARY: ThreadSanitizer: data race /home/anoyes/workspace/foundationdb/flow/Net2.actor.cpp:1734:6 in N2::Net2::onMainThread(Promise<Void>&&, TaskPriority)
3: ==================
3: ThreadSanitizer: reported 1 warnings
2021-03-19 07:23:50 +08:00
|
|
|
std::atomic<bool> stopped;
|
2020-06-21 10:03:33 +08:00
|
|
|
mutable std::map<IPAddress, bool> addressOnHostCache;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-07-24 08:18:13 +08:00
|
|
|
#ifdef ENABLE_SAMPLING
|
2021-06-04 06:10:04 +08:00
|
|
|
ActorLineageSet actorLineageSet;
|
2021-07-24 08:18:13 +08:00
|
|
|
#endif
|
2021-06-04 06:10:04 +08:00
|
|
|
|
2020-05-23 04:31:06 +08:00
|
|
|
std::atomic<bool> started;
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
uint64_t numYields;
|
|
|
|
|
2020-02-08 06:34:24 +08:00
|
|
|
NetworkMetrics::PriorityStats* lastPriorityStats;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-01-20 09:13:27 +08:00
|
|
|
ReadyQueue<OrderedTask> ready;
|
2017-05-26 04:48:44 +08:00
|
|
|
ThreadSafeQueue<OrderedTask> threadReady;
|
|
|
|
|
|
|
|
struct DelayedTask : OrderedTask {
|
|
|
|
double at;
|
2021-03-11 02:06:03 +08:00
|
|
|
DelayedTask(double at, int64_t priority, TaskPriority taskID, Task* task)
|
2021-07-25 02:20:51 +08:00
|
|
|
: OrderedTask(priority, taskID, task), at(at) {}
|
2021-03-11 02:06:03 +08:00
|
|
|
bool operator<(DelayedTask const& rhs) const { return at > rhs.at; } // Ordering is reversed for priority_queue
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
std::priority_queue<DelayedTask, std::vector<DelayedTask>> timers;
|
|
|
|
|
2019-06-25 17:47:35 +08:00
|
|
|
void checkForSlowTask(int64_t tscBegin, int64_t tscEnd, double duration, TaskPriority priority);
|
2020-02-08 02:35:09 +08:00
|
|
|
bool check_yield(TaskPriority taskId, int64_t tscNow);
|
2017-05-26 04:48:44 +08:00
|
|
|
void processThreadReady();
|
2021-03-11 02:06:03 +08:00
|
|
|
void trackAtPriority(TaskPriority priority, double now);
|
2017-05-26 04:48:44 +08:00
|
|
|
void stopImmediately() {
|
2021-03-11 05:24:55 +08:00
|
|
|
#ifdef ADDRESS_SANITIZER
|
|
|
|
// Do leak check before intentionally leaking a bunch of memory
|
|
|
|
__lsan_do_leak_check();
|
|
|
|
#endif
|
2021-03-11 02:06:03 +08:00
|
|
|
stopped = true;
|
|
|
|
decltype(ready) _1;
|
|
|
|
ready.swap(_1);
|
|
|
|
decltype(timers) _2;
|
|
|
|
timers.swap(_2);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<Void> timeOffsetLogger;
|
|
|
|
Future<Void> logTimeOffset();
|
|
|
|
|
|
|
|
Int64MetricHandle bytesReceived;
|
2020-08-07 04:06:50 +08:00
|
|
|
Int64MetricHandle udpBytesReceived;
|
2017-05-26 04:48:44 +08:00
|
|
|
Int64MetricHandle countWriteProbes;
|
|
|
|
Int64MetricHandle countReadProbes;
|
|
|
|
Int64MetricHandle countReads;
|
2020-08-07 04:06:50 +08:00
|
|
|
Int64MetricHandle countUDPReads;
|
2017-05-26 04:48:44 +08:00
|
|
|
Int64MetricHandle countWouldBlock;
|
|
|
|
Int64MetricHandle countWrites;
|
2020-08-07 04:06:50 +08:00
|
|
|
Int64MetricHandle countUDPWrites;
|
2017-05-26 04:48:44 +08:00
|
|
|
Int64MetricHandle countRunLoop;
|
|
|
|
Int64MetricHandle countCantSleep;
|
|
|
|
Int64MetricHandle countWontSleep;
|
|
|
|
Int64MetricHandle countTimers;
|
|
|
|
Int64MetricHandle countTasks;
|
|
|
|
Int64MetricHandle countYields;
|
|
|
|
Int64MetricHandle countYieldBigStack;
|
|
|
|
Int64MetricHandle countYieldCalls;
|
|
|
|
Int64MetricHandle countYieldCallsTrue;
|
|
|
|
Int64MetricHandle countASIOEvents;
|
2020-01-29 04:09:37 +08:00
|
|
|
Int64MetricHandle countRunLoopProfilingSignals;
|
2020-03-13 17:24:37 +08:00
|
|
|
Int64MetricHandle countTLSPolicyFailures;
|
2017-05-26 04:48:44 +08:00
|
|
|
Int64MetricHandle priorityMetric;
|
2019-08-29 05:35:48 +08:00
|
|
|
DoubleMetricHandle countLaunchTime;
|
|
|
|
DoubleMetricHandle countReactTime;
|
2017-05-26 04:48:44 +08:00
|
|
|
BoolMetricHandle awakeMetric;
|
|
|
|
|
|
|
|
EventMetricHandle<SlowTask> slowTaskMetric;
|
2017-12-21 17:58:15 +08:00
|
|
|
|
|
|
|
std::vector<std::string> blobCredentialFiles;
|
2020-04-20 17:53:07 +08:00
|
|
|
std::vector<std::function<void()>> stopCallbacks;
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
|
2019-02-27 10:04:03 +08:00
|
|
|
static boost::asio::ip::address tcpAddress(IPAddress const& n) {
|
|
|
|
if (n.isV6()) {
|
|
|
|
return boost::asio::ip::address_v6(n.toV6());
|
|
|
|
} else {
|
|
|
|
return boost::asio::ip::address_v4(n.toV4());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-07 04:06:50 +08:00
|
|
|
static IPAddress toIPAddress(boost::asio::ip::address const& addr) {
|
|
|
|
if (addr.is_v4()) {
|
|
|
|
return IPAddress(addr.to_v4().to_uint());
|
|
|
|
} else {
|
|
|
|
return IPAddress(addr.to_v6().to_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
static tcp::endpoint tcpEndpoint(NetworkAddress const& n) {
|
2019-02-27 10:04:03 +08:00
|
|
|
return tcp::endpoint(tcpAddress(n.ip), n.port);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2020-08-07 04:06:50 +08:00
|
|
|
static udp::endpoint udpEndpoint(NetworkAddress const& n) {
|
|
|
|
return udp::endpoint(tcpAddress(n.ip), n.port);
|
|
|
|
}
|
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
class BindPromise {
|
|
|
|
Promise<Void> p;
|
|
|
|
const char* errContext;
|
|
|
|
UID errID;
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
2021-03-11 02:06:03 +08:00
|
|
|
BindPromise(const char* errContext, UID errID) : errContext(errContext), errID(errID) {}
|
|
|
|
BindPromise(BindPromise const& r) : p(r.p), errContext(r.errContext), errID(r.errID) {}
|
2020-06-10 08:33:41 +08:00
|
|
|
BindPromise(BindPromise&& r) noexcept : p(std::move(r.p)), errContext(r.errContext), errID(r.errID) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
Future<Void> getFuture() { return p.getFuture(); }
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void operator()(const boost::system::error_code& error, size_t bytesWritten = 0) {
|
2017-05-26 04:48:44 +08:00
|
|
|
try {
|
|
|
|
if (error) {
|
|
|
|
// Log the error...
|
2020-04-19 11:39:02 +08:00
|
|
|
{
|
|
|
|
TraceEvent evt(SevWarn, errContext, errID);
|
|
|
|
evt.suppressFor(1.0).detail("ErrorCode", error.value()).detail("Message", error.message());
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
2020-04-19 11:39:02 +08:00
|
|
|
// There is no function in OpenSSL to use to check if an error code is from OpenSSL,
|
|
|
|
// but all OpenSSL errors have a non-zero "library" code set in bits 24-32, and linux
|
|
|
|
// error codes should never go that high.
|
|
|
|
if (error.value() >= (1 << 24L)) {
|
|
|
|
evt.detail("WhichMeans", TLSPolicy::ErrorString(error));
|
|
|
|
}
|
2020-02-20 10:37:47 +08:00
|
|
|
#endif
|
2020-04-19 11:39:02 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
|
|
|
|
p.sendError(connection_failed());
|
2017-05-26 04:48:44 +08:00
|
|
|
} else
|
2021-03-11 02:06:03 +08:00
|
|
|
p.send(Void());
|
2017-05-26 04:48:44 +08:00
|
|
|
} catch (Error& e) {
|
|
|
|
p.sendError(e);
|
|
|
|
} catch (...) {
|
|
|
|
p.sendError(unknown_error());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
class Connection final : public IConnection, ReferenceCounted<Connection> {
|
2017-05-26 04:48:44 +08:00
|
|
|
public:
|
2020-11-28 02:10:41 +08:00
|
|
|
void addref() override { ReferenceCounted<Connection>::addref(); }
|
|
|
|
void delref() override { ReferenceCounted<Connection>::delref(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void close() override { closeSocket(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
explicit Connection(boost::asio::io_service& io_service)
|
|
|
|
: id(nondeterministicRandom()->randomUniqueID()), socket(io_service) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// This is not part of the IConnection interface, because it is wrapped by INetwork::connect()
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Reference<IConnection>> connect(boost::asio::io_service* ios, NetworkAddress addr) {
|
|
|
|
state Reference<Connection> self(new Connection(*ios));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
self->peer_address = addr;
|
|
|
|
try {
|
|
|
|
auto to = tcpEndpoint(addr);
|
|
|
|
BindPromise p("N2_ConnectError", self->id);
|
|
|
|
Future<Void> onConnected = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
self->socket.async_connect(to, std::move(p));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
wait(onConnected);
|
2017-05-26 04:48:44 +08:00
|
|
|
self->init();
|
|
|
|
return self;
|
|
|
|
} catch (Error&) {
|
|
|
|
// Either the connection failed, or was cancelled by the caller
|
|
|
|
self->closeSocket();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is not part of the IConnection interface, because it is wrapped by IListener::accept()
|
|
|
|
void accept(NetworkAddress peerAddr) {
|
|
|
|
this->peer_address = peerAddr;
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Void> acceptHandshake() override { return Void(); }
|
2020-02-07 08:45:54 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Void> connectHandshake() override { return Void(); }
|
2020-02-07 08:45:54 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
// returns when write() can write at least one byte
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Void> onWritable() override {
|
2017-05-26 04:48:44 +08:00
|
|
|
++g_net2->countWriteProbes;
|
|
|
|
BindPromise p("N2_WriteProbeError", id);
|
|
|
|
auto f = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
socket.async_write_some(boost::asio::null_buffers(), std::move(p));
|
2017-05-26 04:48:44 +08:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns when read() can read at least one byte
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Void> onReadable() override {
|
2017-05-26 04:48:44 +08:00
|
|
|
++g_net2->countReadProbes;
|
|
|
|
BindPromise p("N2_ReadProbeError", id);
|
|
|
|
auto f = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
socket.async_read_some(boost::asio::null_buffers(), std::move(p));
|
2017-05-26 04:48:44 +08:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Reads as many bytes as possible from the read buffer into [begin,end) and returns the number of bytes read (might
|
|
|
|
// be 0)
|
|
|
|
int read(uint8_t* begin, uint8_t* end) override {
|
2017-05-26 04:48:44 +08:00
|
|
|
boost::system::error_code err;
|
|
|
|
++g_net2->countReads;
|
2021-03-11 02:06:03 +08:00
|
|
|
size_t toRead = end - begin;
|
|
|
|
size_t size = socket.read_some(boost::asio::mutable_buffers_1(begin, toRead), err);
|
2017-05-26 04:48:44 +08:00
|
|
|
g_net2->bytesReceived += size;
|
|
|
|
//TraceEvent("ConnRead", this->id).detail("Bytes", size);
|
|
|
|
if (err) {
|
|
|
|
if (err == boost::asio::error::would_block) {
|
|
|
|
++g_net2->countWouldBlock;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
onReadError(err);
|
|
|
|
throw connection_failed();
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
ASSERT(size); // If the socket is closed, we expect an 'eof' error, not a zero return value
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Writes as many bytes as possible from the given SendBuffer chain into the write buffer and returns the number of
|
|
|
|
// bytes written (might be 0)
|
|
|
|
int write(SendBuffer const* data, int limit) override {
|
2017-05-26 04:48:44 +08:00
|
|
|
boost::system::error_code err;
|
|
|
|
++g_net2->countWrites;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
size_t sent = socket.write_some(
|
|
|
|
boost::iterator_range<SendBufferIterator>(SendBufferIterator(data, limit), SendBufferIterator()), err);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
if (err) {
|
2021-03-11 02:06:03 +08:00
|
|
|
// Since there was an error, sent's value can't be used to infer that the buffer has data and the limit is
|
|
|
|
// positive so check explicitly.
|
2017-05-26 04:48:44 +08:00
|
|
|
ASSERT(limit > 0);
|
|
|
|
bool notEmpty = false;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (auto p = data; p; p = p->next)
|
|
|
|
if (p->bytes_written - p->bytes_sent > 0) {
|
2017-05-26 04:48:44 +08:00
|
|
|
notEmpty = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ASSERT(notEmpty);
|
|
|
|
|
|
|
|
if (err == boost::asio::error::would_block) {
|
|
|
|
++g_net2->countWouldBlock;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
onWriteError(err);
|
|
|
|
throw connection_failed();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ASSERT(sent); // Make sure data was sent, and also this check will fail if the buffer chain was empty or the
|
|
|
|
// limit was not > 0.
|
2017-05-26 04:48:44 +08:00
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
NetworkAddress getPeerAddress() const override { return peer_address; }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
UID getDebugID() const override { return id; }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
tcp::socket& getSocket() { return socket; }
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
private:
|
|
|
|
UID id;
|
|
|
|
tcp::socket socket;
|
|
|
|
NetworkAddress peer_address;
|
|
|
|
|
|
|
|
void init() {
|
|
|
|
// Socket settings that have to be set after connect or accept succeeds
|
2018-04-23 18:49:49 +08:00
|
|
|
socket.non_blocking(true);
|
2019-08-24 02:07:46 +08:00
|
|
|
if (FLOW_KNOBS->FLOW_TCP_NODELAY & 1) {
|
2021-03-11 02:06:03 +08:00
|
|
|
socket.set_option(boost::asio::ip::tcp::no_delay(true));
|
2019-08-24 02:07:46 +08:00
|
|
|
}
|
|
|
|
if (FLOW_KNOBS->FLOW_TCP_QUICKACK & 1) {
|
|
|
|
#ifdef __linux__
|
2021-03-11 02:06:03 +08:00
|
|
|
socket.set_option(boost::asio::detail::socket_option::boolean<IPPROTO_TCP, TCP_QUICKACK>(true));
|
2019-08-24 02:07:46 +08:00
|
|
|
#else
|
2021-03-11 02:06:03 +08:00
|
|
|
TraceEvent(SevWarn, "N2_InitWarn").detail("Message", "TCP_QUICKACK not supported");
|
2019-08-24 02:07:46 +08:00
|
|
|
#endif
|
|
|
|
}
|
2019-06-19 07:34:35 +08:00
|
|
|
platform::setCloseOnExec(socket.native_handle());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void closeSocket() {
|
|
|
|
boost::system::error_code error;
|
|
|
|
socket.close(error);
|
|
|
|
if (error)
|
2021-03-11 02:06:03 +08:00
|
|
|
TraceEvent(SevWarn, "N2_CloseError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void onReadError(const boost::system::error_code& error) {
|
|
|
|
TraceEvent(SevWarn, "N2_ReadError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
2017-05-26 04:48:44 +08:00
|
|
|
closeSocket();
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
void onWriteError(const boost::system::error_code& error) {
|
|
|
|
TraceEvent(SevWarn, "N2_WriteError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
2017-05-26 04:48:44 +08:00
|
|
|
closeSocket();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-08-07 04:06:50 +08:00
|
|
|
class ReadPromise {
|
|
|
|
Promise<int> p;
|
|
|
|
const char* errContext;
|
|
|
|
UID errID;
|
|
|
|
std::shared_ptr<udp::endpoint> endpoint = nullptr;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ReadPromise(const char* errContext, UID errID) : errContext(errContext), errID(errID) {}
|
|
|
|
ReadPromise(ReadPromise const& other) = default;
|
|
|
|
ReadPromise(ReadPromise&& other) : p(std::move(other.p)), errContext(other.errContext), errID(other.errID) {}
|
|
|
|
|
|
|
|
std::shared_ptr<udp::endpoint>& getEndpoint() { return endpoint; }
|
|
|
|
|
|
|
|
Future<int> getFuture() { return p.getFuture(); }
|
|
|
|
void operator()(const boost::system::error_code& error, size_t bytesWritten) {
|
|
|
|
try {
|
|
|
|
if (error) {
|
|
|
|
TraceEvent evt(SevWarn, errContext, errID);
|
|
|
|
evt.suppressFor(1.0).detail("ErrorCode", error.value()).detail("Message", error.message());
|
|
|
|
p.sendError(connection_failed());
|
|
|
|
} else {
|
|
|
|
p.send(int(bytesWritten));
|
|
|
|
}
|
|
|
|
} catch (Error& e) {
|
|
|
|
p.sendError(e);
|
|
|
|
} catch (...) {
|
|
|
|
p.sendError(unknown_error());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class UDPSocket : public IUDPSocket, ReferenceCounted<UDPSocket> {
|
|
|
|
UID id;
|
|
|
|
Optional<NetworkAddress> toAddress;
|
|
|
|
udp::socket socket;
|
|
|
|
bool isPublic = false;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ACTOR static Future<Reference<IUDPSocket>> connect(boost::asio::io_service* io_service,
|
2021-03-11 02:06:03 +08:00
|
|
|
Optional<NetworkAddress> toAddress,
|
|
|
|
bool isV6) {
|
2020-08-07 04:06:50 +08:00
|
|
|
state Reference<UDPSocket> self(new UDPSocket(*io_service, toAddress, isV6));
|
|
|
|
ASSERT(!toAddress.present() || toAddress.get().ip.isV6() == isV6);
|
|
|
|
if (!toAddress.present()) {
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
if (toAddress.present()) {
|
|
|
|
auto to = udpEndpoint(toAddress.get());
|
|
|
|
BindPromise p("N2_UDPConnectError", self->id);
|
|
|
|
Future<Void> onConnected = p.getFuture();
|
|
|
|
self->socket.async_connect(to, std::move(p));
|
|
|
|
|
|
|
|
wait(onConnected);
|
|
|
|
}
|
|
|
|
self->init();
|
|
|
|
return self;
|
|
|
|
} catch (...) {
|
|
|
|
self->closeSocket();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void close() override { closeSocket(); }
|
|
|
|
|
|
|
|
Future<int> receive(uint8_t* begin, uint8_t* end) override {
|
|
|
|
++g_net2->countUDPReads;
|
|
|
|
ReadPromise p("N2_UDPReadError", id);
|
|
|
|
auto res = p.getFuture();
|
|
|
|
socket.async_receive(boost::asio::mutable_buffer(begin, end - begin), std::move(p));
|
|
|
|
return fmap(
|
|
|
|
[](int bytes) {
|
|
|
|
g_net2->udpBytesReceived += bytes;
|
|
|
|
return bytes;
|
|
|
|
},
|
|
|
|
res);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<int> receiveFrom(uint8_t* begin, uint8_t* end, NetworkAddress* sender) override {
|
|
|
|
++g_net2->countUDPReads;
|
|
|
|
ReadPromise p("N2_UDPReadFromError", id);
|
|
|
|
p.getEndpoint() = std::make_shared<udp::endpoint>();
|
|
|
|
auto endpoint = p.getEndpoint().get();
|
|
|
|
auto res = p.getFuture();
|
|
|
|
socket.async_receive_from(boost::asio::mutable_buffer(begin, end - begin), *endpoint, std::move(p));
|
|
|
|
return fmap(
|
|
|
|
[endpoint, sender](int bytes) {
|
|
|
|
if (sender) {
|
|
|
|
sender->port = endpoint->port();
|
|
|
|
sender->ip = toIPAddress(endpoint->address());
|
|
|
|
}
|
|
|
|
g_net2->udpBytesReceived += bytes;
|
|
|
|
return bytes;
|
|
|
|
},
|
|
|
|
res);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<int> send(uint8_t const* begin, uint8_t const* end) override {
|
|
|
|
++g_net2->countUDPWrites;
|
|
|
|
ReadPromise p("N2_UDPWriteError", id);
|
|
|
|
auto res = p.getFuture();
|
|
|
|
socket.async_send(boost::asio::const_buffer(begin, end - begin), std::move(p));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<int> sendTo(uint8_t const* begin, uint8_t const* end, NetworkAddress const& peer) override {
|
|
|
|
++g_net2->countUDPWrites;
|
|
|
|
ReadPromise p("N2_UDPWriteError", id);
|
|
|
|
auto res = p.getFuture();
|
|
|
|
udp::endpoint toEndpoint = udpEndpoint(peer);
|
|
|
|
socket.async_send_to(boost::asio::const_buffer(begin, end - begin), toEndpoint, std::move(p));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void bind(NetworkAddress const& addr) override {
|
|
|
|
boost::system::error_code ec;
|
|
|
|
socket.bind(udpEndpoint(addr), ec);
|
|
|
|
if (ec) {
|
|
|
|
Error x;
|
|
|
|
if (ec.value() == EADDRINUSE)
|
|
|
|
x = address_in_use();
|
|
|
|
else if (ec.value() == EADDRNOTAVAIL)
|
|
|
|
x = invalid_local_address();
|
|
|
|
else
|
|
|
|
x = bind_failed();
|
|
|
|
TraceEvent(SevWarnAlways, "Net2UDPBindError").error(x);
|
|
|
|
throw x;
|
|
|
|
}
|
|
|
|
isPublic = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
UID getDebugID() const override { return id; }
|
|
|
|
|
|
|
|
void addref() override { ReferenceCounted<UDPSocket>::addref(); }
|
|
|
|
void delref() override { ReferenceCounted<UDPSocket>::delref(); }
|
|
|
|
|
2020-11-17 03:40:06 +08:00
|
|
|
NetworkAddress localAddress() const override {
|
2020-08-07 04:06:50 +08:00
|
|
|
auto endpoint = socket.local_endpoint();
|
|
|
|
return NetworkAddress(toIPAddress(endpoint.address()), endpoint.port(), isPublic, false);
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
boost::asio::ip::udp::socket::native_handle_type native_handle() override { return socket.native_handle(); }
|
2020-11-17 03:40:06 +08:00
|
|
|
|
2020-08-07 04:06:50 +08:00
|
|
|
private:
|
|
|
|
UDPSocket(boost::asio::io_service& io_service, Optional<NetworkAddress> toAddress, bool isV6)
|
2021-03-11 02:06:03 +08:00
|
|
|
: id(nondeterministicRandom()->randomUniqueID()), socket(io_service, isV6 ? udp::v6() : udp::v4()) {}
|
2020-08-07 04:06:50 +08:00
|
|
|
|
|
|
|
void closeSocket() {
|
|
|
|
boost::system::error_code error;
|
|
|
|
socket.close(error);
|
|
|
|
if (error)
|
|
|
|
TraceEvent(SevWarn, "N2_CloseError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
|
|
|
}
|
|
|
|
|
|
|
|
void onReadError(const boost::system::error_code& error) {
|
|
|
|
TraceEvent(SevWarn, "N2_UDPReadError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
|
|
|
closeSocket();
|
|
|
|
}
|
|
|
|
void onWriteError(const boost::system::error_code& error) {
|
|
|
|
TraceEvent(SevWarn, "N2_UDPWriteError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
|
|
|
closeSocket();
|
|
|
|
}
|
|
|
|
|
|
|
|
void init() {
|
|
|
|
socket.non_blocking(true);
|
|
|
|
platform::setCloseOnExec(socket.native_handle());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
class Listener final : public IListener, ReferenceCounted<Listener> {
|
2020-03-05 06:26:01 +08:00
|
|
|
boost::asio::io_context& io_service;
|
2017-05-26 04:48:44 +08:00
|
|
|
NetworkAddress listenAddress;
|
|
|
|
tcp::acceptor acceptor;
|
|
|
|
|
|
|
|
public:
|
2021-03-11 02:06:03 +08:00
|
|
|
Listener(boost::asio::io_context& io_service, NetworkAddress listenAddress)
|
|
|
|
: io_service(io_service), listenAddress(listenAddress), acceptor(io_service, tcpEndpoint(listenAddress)) {
|
Remote ikvs debugging (#6465)
* initial structure for remote IKVS server
* moved struct to .h file, added new files to CMakeList
* happy path implementation, connection error when testing
* saved minor local change
* changed tracing to debug
* fixed onClosed and getError being called before init is finished
* fix spawn process bug, now use absolute path
* added server knob to set ikvs process port number
* added server knob for remote/local kv store
* implement simulator remote process spawning
* fixed bug for simulator timeout
* commit all changes
* removed print lines in trace
* added FlowProcess implementation by Markus
* initial debug of FlowProcess, stuck at parent sending OpenKVStoreRequest to child
* temporary fix for process factory throwing segfault on create
* specify public address in command
* change remote kv store knob to false for jenkins build
* made port 0 open random unused port
* change remote store knob to true for benchmark
* set listening port to randomly opened port
* added print lines for jenkins run open kv store timeout debug
* removed most tracing and print lines
* removed tutorial changes
* update handleIOErrors error handling to handle remote-ikvs cases
* Push all debugging changes
* A version where worker bug exists
* A version where restarting tests fail
* Use both the name and the port to determine the child process
* Remove unnecessary update on local address
* Disable remote-kvs for DiskFailureCycle test
* A version where restarting stuck
* A version where most restarting tests green
* Reset connection with child process explicitly
* Remove change on unnecessary files
* Unify flags from _ to -
* fix merging unexpected changes
* fix trac.error to .errorUnsuppressed
* Add license header
* Remove unnecessary header in FlowProcess.actor.cpp
* Fix Windows build
* Fix Windows build, add missing ;
* Fix a stupid bug caused by code dropped by code merging
* Disable remote kvs by default
* Pass the conn_file path to the flow process, though not needed, but the buildNetwork is difficult to tune
* serialization change on readrange
* Update traces
* Refactor the RemoteIKVS interface
* Format files
* Update sim2 interface to not clog connections between parent and child processes in simulation
* Update comments; remove debugging symbols; Add error handling for remote_kvs_cancelled
* Add comments, format files
* Change method name from isBuggifyDisabled to isStableConnection; Decrease(0.1x) latency for stable connections
* Commit the IConnection interface change, forgot in previous commit
* Fix the issue that onClosed request is cancelled by ActorCollection
* Enable the remote kv store knob
* Remove FlowProcess.actor.cpp and move functions to RemoteIKeyValueStore.actor.cpp; Add remote kv store delay to avoid race; Bind the child process to die with parent process
* Fix the bug where one process starts storage server more than once
* Add a please_reboot_remote_kv_store error to restart the storage server worker if remote kvs died abnormally
* Remove unreachable code path and add comments
* Clang format the code
* Fix a simple wait error
* Clang format after merging the main branch
* Testing mixed mode in simulation if remote_kvs knob is enabled, setting the default to false
* Disable remote kvs for PhysicalShardMove which is for RocksDB
* Cleanup #include orders, remove debugging traces
* Revert the reorder in fdbserver.actor.cpp, which fails the gcc build
Co-authored-by: “Lincoln <“lincoln.xiao@snowflake.com”>
2022-04-01 08:08:59 +08:00
|
|
|
// when port 0 is passed in, a random port will be opened
|
|
|
|
// set listenAddress as the address with the actual port opened instead of port 0
|
|
|
|
if (listenAddress.port == 0) {
|
|
|
|
this->listenAddress =
|
|
|
|
NetworkAddress::parse(acceptor.local_endpoint().address().to_string().append(":").append(
|
|
|
|
std::to_string(acceptor.local_endpoint().port())));
|
|
|
|
}
|
2019-06-19 07:40:17 +08:00
|
|
|
platform::setCloseOnExec(acceptor.native_handle());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2020-11-28 02:10:41 +08:00
|
|
|
void addref() override { ReferenceCounted<Listener>::addref(); }
|
|
|
|
void delref() override { ReferenceCounted<Listener>::delref(); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// Returns one incoming connection when it is available
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Reference<IConnection>> accept() override { return doAccept(this); }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
NetworkAddress getListenAddress() const override { return listenAddress; }
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
private:
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Reference<IConnection>> doAccept(Listener* self) {
|
|
|
|
state Reference<Connection> conn(new Connection(self->io_service));
|
2017-05-26 04:48:44 +08:00
|
|
|
state tcp::acceptor::endpoint_type peer_endpoint;
|
|
|
|
try {
|
|
|
|
BindPromise p("N2_AcceptError", UID());
|
|
|
|
auto f = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
self->acceptor.async_accept(conn->getSocket(), peer_endpoint, std::move(p));
|
|
|
|
wait(f);
|
2019-02-27 10:04:03 +08:00
|
|
|
auto peer_address = peer_endpoint.address().is_v6() ? IPAddress(peer_endpoint.address().to_v6().to_bytes())
|
|
|
|
: IPAddress(peer_endpoint.address().to_v4().to_ulong());
|
|
|
|
conn->accept(NetworkAddress(peer_address, peer_endpoint.port()));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
return conn;
|
|
|
|
} catch (...) {
|
|
|
|
conn->close();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
|
|
|
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket&> ssl_socket;
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
struct SSLHandshakerThread final : IThreadPoolReceiver {
|
2020-06-21 21:17:55 +08:00
|
|
|
SSLHandshakerThread() {}
|
2020-11-23 12:09:10 +08:00
|
|
|
void init() override {}
|
2020-06-21 21:17:55 +08:00
|
|
|
|
2020-10-08 12:58:24 +08:00
|
|
|
struct Handshake final : TypedAction<SSLHandshakerThread, Handshake> {
|
2021-03-11 02:06:03 +08:00
|
|
|
Handshake(ssl_socket& socket, ssl_socket::handshake_type type) : socket(socket), type(type) {}
|
2020-10-08 09:41:19 +08:00
|
|
|
double getTimeEstimate() const override { return 0.001; }
|
2020-06-21 21:17:55 +08:00
|
|
|
|
|
|
|
ThreadReturnPromise<Void> done;
|
2021-03-11 02:06:03 +08:00
|
|
|
ssl_socket& socket;
|
2020-06-21 21:17:55 +08:00
|
|
|
ssl_socket::handshake_type type;
|
|
|
|
boost::system::error_code err;
|
|
|
|
};
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void action(Handshake& h) {
|
2020-06-21 21:17:55 +08:00
|
|
|
try {
|
|
|
|
h.socket.next_layer().non_blocking(false, h.err);
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!h.err.failed()) {
|
2020-06-21 21:17:55 +08:00
|
|
|
h.socket.handshake(h.type, h.err);
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!h.err.failed()) {
|
2020-06-21 21:17:55 +08:00
|
|
|
h.socket.next_layer().non_blocking(true, h.err);
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
if (h.err.failed()) {
|
|
|
|
TraceEvent(SevWarn,
|
|
|
|
h.type == ssl_socket::handshake_type::client ? "N2_ConnectHandshakeError"
|
|
|
|
: "N2_AcceptHandshakeError")
|
|
|
|
.detail("ErrorCode", h.err.value())
|
|
|
|
.detail("ErrorMsg", h.err.message().c_str())
|
|
|
|
.detail("BackgroundThread", true);
|
2020-06-21 21:17:55 +08:00
|
|
|
h.done.sendError(connection_failed());
|
|
|
|
} else {
|
|
|
|
h.done.send(Void());
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (...) {
|
|
|
|
TraceEvent(SevWarn,
|
|
|
|
h.type == ssl_socket::handshake_type::client ? "N2_ConnectHandshakeUnknownError"
|
|
|
|
: "N2_AcceptHandshakeUnknownError")
|
|
|
|
.detail("BackgroundThread", true);
|
2020-06-21 21:17:55 +08:00
|
|
|
h.done.sendError(connection_failed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
class SSLConnection final : public IConnection, ReferenceCounted<SSLConnection> {
|
2020-02-05 06:56:40 +08:00
|
|
|
public:
|
2020-11-28 02:10:41 +08:00
|
|
|
void addref() override { ReferenceCounted<SSLConnection>::addref(); }
|
|
|
|
void delref() override { ReferenceCounted<SSLConnection>::delref(); }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void close() override { closeSocket(); }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
explicit SSLConnection(boost::asio::io_service& io_service,
|
|
|
|
Reference<ReferencedObject<boost::asio::ssl::context>> context)
|
|
|
|
: id(nondeterministicRandom()->randomUniqueID()), socket(io_service), ssl_sock(socket, context->mutate()),
|
|
|
|
sslContext(context) {}
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2020-02-07 08:45:54 +08:00
|
|
|
// This is not part of the IConnection interface, because it is wrapped by INetwork::connect()
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Reference<IConnection>> connect(boost::asio::io_service* ios,
|
|
|
|
Reference<ReferencedObject<boost::asio::ssl::context>> context,
|
|
|
|
NetworkAddress addr) {
|
|
|
|
std::pair<IPAddress, uint16_t> peerIP = std::make_pair(addr.ip, addr.port);
|
2020-02-07 08:45:54 +08:00
|
|
|
auto iter(g_network->networkInfo.serverTLSConnectionThrottler.find(peerIP));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (iter != g_network->networkInfo.serverTLSConnectionThrottler.end()) {
|
2020-02-07 08:45:54 +08:00
|
|
|
if (now() < iter->second.second) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (iter->second.first >= FLOW_KNOBS->TLS_CLIENT_CONNECTION_THROTTLE_ATTEMPTS) {
|
2020-02-07 08:45:54 +08:00
|
|
|
TraceEvent("TLSOutgoingConnectionThrottlingWarning").suppressFor(1.0).detail("PeerIP", addr);
|
|
|
|
wait(delay(FLOW_KNOBS->CONNECTION_MONITOR_TIMEOUT));
|
|
|
|
throw connection_failed();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
g_network->networkInfo.serverTLSConnectionThrottler.erase(peerIP);
|
|
|
|
}
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
|
|
|
|
state Reference<SSLConnection> self(new SSLConnection(*ios, context));
|
2020-02-07 08:45:54 +08:00
|
|
|
self->peer_address = addr;
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2020-02-05 06:56:40 +08:00
|
|
|
try {
|
2020-02-05 09:54:03 +08:00
|
|
|
auto to = tcpEndpoint(self->peer_address);
|
2020-02-05 06:56:40 +08:00
|
|
|
BindPromise p("N2_ConnectError", self->id);
|
|
|
|
Future<Void> onConnected = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
self->socket.async_connect(to, std::move(p));
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
wait(onConnected);
|
2020-02-07 08:45:54 +08:00
|
|
|
self->init();
|
|
|
|
return self;
|
|
|
|
} catch (Error& e) {
|
|
|
|
// Either the connection failed, or was cancelled by the caller
|
|
|
|
self->closeSocket();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is not part of the IConnection interface, because it is wrapped by IListener::accept()
|
|
|
|
void accept(NetworkAddress peerAddr) {
|
|
|
|
this->peer_address = peerAddr;
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static void doAcceptHandshake(Reference<SSLConnection> self, Promise<Void> connected) {
|
2020-06-23 14:45:47 +08:00
|
|
|
state Hold<int> holder;
|
2020-06-21 21:17:55 +08:00
|
|
|
|
2020-02-07 08:45:54 +08:00
|
|
|
try {
|
2020-06-21 21:17:55 +08:00
|
|
|
Future<Void> onHandshook;
|
|
|
|
|
|
|
|
// If the background handshakers are not all busy, use one
|
2021-03-11 02:06:03 +08:00
|
|
|
if (N2::g_net2->sslPoolHandshakesInProgress < N2::g_net2->sslHandshakerThreadsStarted) {
|
2020-06-23 14:45:47 +08:00
|
|
|
holder = Hold(&N2::g_net2->sslPoolHandshakesInProgress);
|
2021-03-11 02:06:03 +08:00
|
|
|
auto handshake =
|
|
|
|
new SSLHandshakerThread::Handshake(self->ssl_sock, boost::asio::ssl::stream_base::server);
|
2020-06-21 21:17:55 +08:00
|
|
|
onHandshook = handshake->done.getFuture();
|
|
|
|
N2::g_net2->sslHandshakerPool->post(handshake);
|
2021-03-11 02:06:03 +08:00
|
|
|
} else {
|
2020-06-21 21:17:55 +08:00
|
|
|
// Otherwise use flow network thread
|
|
|
|
BindPromise p("N2_AcceptHandshakeError", UID());
|
|
|
|
onHandshook = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
self->ssl_sock.async_handshake(boost::asio::ssl::stream_base::server, std::move(p));
|
2020-06-21 21:17:55 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
wait(onHandshook);
|
2020-02-21 02:11:43 +08:00
|
|
|
wait(delay(0, TaskPriority::Handshake));
|
2020-02-05 09:54:03 +08:00
|
|
|
connected.send(Void());
|
2020-02-07 08:45:54 +08:00
|
|
|
} catch (...) {
|
|
|
|
self->closeSocket();
|
|
|
|
connected.sendError(connection_failed());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Void> acceptHandshakeWrapper(Reference<SSLConnection> self) {
|
|
|
|
state std::pair<IPAddress, uint16_t> peerIP;
|
2020-10-06 06:24:03 +08:00
|
|
|
peerIP = std::make_pair(self->getPeerAddress().ip, static_cast<uint16_t>(0));
|
|
|
|
auto iter(g_network->networkInfo.serverTLSConnectionThrottler.find(peerIP));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (iter != g_network->networkInfo.serverTLSConnectionThrottler.end()) {
|
2020-10-06 06:24:03 +08:00
|
|
|
if (now() < iter->second.second) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (iter->second.first >= FLOW_KNOBS->TLS_SERVER_CONNECTION_THROTTLE_ATTEMPTS) {
|
|
|
|
TraceEvent("TLSIncomingConnectionThrottlingWarning")
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("PeerIP", peerIP.first.toString());
|
2020-10-06 06:24:03 +08:00
|
|
|
wait(delay(FLOW_KNOBS->CONNECTION_MONITOR_TIMEOUT));
|
|
|
|
self->closeSocket();
|
|
|
|
throw connection_failed();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
g_network->networkInfo.serverTLSConnectionThrottler.erase(peerIP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wait(g_network->networkInfo.handshakeLock->take());
|
|
|
|
state FlowLock::Releaser releaser(*g_network->networkInfo.handshakeLock);
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2020-02-07 08:45:54 +08:00
|
|
|
Promise<Void> connected;
|
|
|
|
doAcceptHandshake(self, connected);
|
|
|
|
try {
|
2020-10-06 06:24:03 +08:00
|
|
|
choose {
|
2021-03-11 02:06:03 +08:00
|
|
|
when(wait(connected.getFuture())) { return Void(); }
|
|
|
|
when(wait(delay(FLOW_KNOBS->CONNECTION_MONITOR_TIMEOUT))) { throw connection_failed(); }
|
2020-10-06 06:24:03 +08:00
|
|
|
}
|
2020-02-05 09:54:03 +08:00
|
|
|
} catch (Error& e) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (e.code() != error_code_actor_cancelled) {
|
2020-10-06 06:24:03 +08:00
|
|
|
auto iter(g_network->networkInfo.serverTLSConnectionThrottler.find(peerIP));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (iter != g_network->networkInfo.serverTLSConnectionThrottler.end()) {
|
2020-10-06 06:24:03 +08:00
|
|
|
iter->second.first++;
|
|
|
|
} else {
|
2021-03-11 02:06:03 +08:00
|
|
|
g_network->networkInfo.serverTLSConnectionThrottler[peerIP] =
|
|
|
|
std::make_pair(0, now() + FLOW_KNOBS->TLS_SERVER_CONNECTION_THROTTLE_TIMEOUT);
|
2020-10-06 06:24:03 +08:00
|
|
|
}
|
|
|
|
}
|
2020-02-05 09:54:03 +08:00
|
|
|
// Either the connection failed, or was cancelled by the caller
|
|
|
|
self->closeSocket();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Void> acceptHandshake() override { return acceptHandshakeWrapper(Reference<SSLConnection>::addRef(this)); }
|
2020-02-07 08:45:54 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static void doConnectHandshake(Reference<SSLConnection> self, Promise<Void> connected) {
|
2020-06-23 14:45:47 +08:00
|
|
|
state Hold<int> holder;
|
2020-02-07 08:45:54 +08:00
|
|
|
|
|
|
|
try {
|
2020-06-21 21:17:55 +08:00
|
|
|
Future<Void> onHandshook;
|
|
|
|
// If the background handshakers are not all busy, use one
|
2021-03-11 02:06:03 +08:00
|
|
|
if (N2::g_net2->sslPoolHandshakesInProgress < N2::g_net2->sslHandshakerThreadsStarted) {
|
2020-06-23 14:45:47 +08:00
|
|
|
holder = Hold(&N2::g_net2->sslPoolHandshakesInProgress);
|
2021-03-11 02:06:03 +08:00
|
|
|
auto handshake =
|
|
|
|
new SSLHandshakerThread::Handshake(self->ssl_sock, boost::asio::ssl::stream_base::client);
|
2020-06-21 21:17:55 +08:00
|
|
|
onHandshook = handshake->done.getFuture();
|
|
|
|
N2::g_net2->sslHandshakerPool->post(handshake);
|
2021-03-11 02:06:03 +08:00
|
|
|
} else {
|
2020-06-21 21:17:55 +08:00
|
|
|
// Otherwise use flow network thread
|
|
|
|
BindPromise p("N2_ConnectHandshakeError", self->id);
|
2020-06-22 20:53:37 +08:00
|
|
|
onHandshook = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
self->ssl_sock.async_handshake(boost::asio::ssl::stream_base::client, std::move(p));
|
2020-06-21 21:17:55 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
wait(onHandshook);
|
2020-02-21 02:11:43 +08:00
|
|
|
wait(delay(0, TaskPriority::Handshake));
|
2020-02-07 08:45:54 +08:00
|
|
|
connected.send(Void());
|
|
|
|
} catch (...) {
|
|
|
|
self->closeSocket();
|
|
|
|
connected.sendError(connection_failed());
|
2020-02-05 09:54:03 +08:00
|
|
|
}
|
2020-02-07 08:45:54 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Void> connectHandshakeWrapper(Reference<SSLConnection> self) {
|
2020-10-06 06:24:03 +08:00
|
|
|
wait(g_network->networkInfo.handshakeLock->take());
|
|
|
|
state FlowLock::Releaser releaser(*g_network->networkInfo.handshakeLock);
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2020-02-05 09:54:03 +08:00
|
|
|
Promise<Void> connected;
|
2020-02-07 08:45:54 +08:00
|
|
|
doConnectHandshake(self, connected);
|
2020-02-05 09:54:03 +08:00
|
|
|
try {
|
2020-10-06 06:24:03 +08:00
|
|
|
choose {
|
2021-03-11 02:06:03 +08:00
|
|
|
when(wait(connected.getFuture())) { return Void(); }
|
|
|
|
when(wait(delay(FLOW_KNOBS->CONNECTION_MONITOR_TIMEOUT))) { throw connection_failed(); }
|
2020-10-06 06:24:03 +08:00
|
|
|
}
|
2020-02-05 06:56:40 +08:00
|
|
|
} catch (Error& e) {
|
|
|
|
// Either the connection failed, or was cancelled by the caller
|
2021-03-11 02:06:03 +08:00
|
|
|
if (e.code() != error_code_actor_cancelled) {
|
|
|
|
std::pair<IPAddress, uint16_t> peerIP = std::make_pair(self->peer_address.ip, self->peer_address.port);
|
2020-10-06 06:24:03 +08:00
|
|
|
auto iter(g_network->networkInfo.serverTLSConnectionThrottler.find(peerIP));
|
2021-03-11 02:06:03 +08:00
|
|
|
if (iter != g_network->networkInfo.serverTLSConnectionThrottler.end()) {
|
2020-10-06 06:24:03 +08:00
|
|
|
iter->second.first++;
|
|
|
|
} else {
|
2021-03-11 02:06:03 +08:00
|
|
|
g_network->networkInfo.serverTLSConnectionThrottler[peerIP] =
|
|
|
|
std::make_pair(0, now() + FLOW_KNOBS->TLS_CLIENT_CONNECTION_THROTTLE_TIMEOUT);
|
2020-10-06 06:24:03 +08:00
|
|
|
}
|
|
|
|
}
|
2020-02-05 06:56:40 +08:00
|
|
|
self->closeSocket();
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Void> connectHandshake() override { return connectHandshakeWrapper(Reference<SSLConnection>::addRef(this)); }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
// returns when write() can write at least one byte
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Void> onWritable() override {
|
2020-02-05 06:56:40 +08:00
|
|
|
++g_net2->countWriteProbes;
|
|
|
|
BindPromise p("N2_WriteProbeError", id);
|
|
|
|
auto f = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
socket.async_write_some(boost::asio::null_buffers(), std::move(p));
|
2020-02-05 06:56:40 +08:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// returns when read() can read at least one byte
|
2020-11-23 12:09:10 +08:00
|
|
|
Future<Void> onReadable() override {
|
2020-02-05 06:56:40 +08:00
|
|
|
++g_net2->countReadProbes;
|
|
|
|
BindPromise p("N2_ReadProbeError", id);
|
|
|
|
auto f = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
socket.async_read_some(boost::asio::null_buffers(), std::move(p));
|
2020-02-05 06:56:40 +08:00
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Reads as many bytes as possible from the read buffer into [begin,end) and returns the number of bytes read (might
|
|
|
|
// be 0)
|
|
|
|
int read(uint8_t* begin, uint8_t* end) override {
|
2020-02-05 06:56:40 +08:00
|
|
|
boost::system::error_code err;
|
|
|
|
++g_net2->countReads;
|
2021-03-11 02:06:03 +08:00
|
|
|
size_t toRead = end - begin;
|
|
|
|
size_t size = ssl_sock.read_some(boost::asio::mutable_buffers_1(begin, toRead), err);
|
2020-02-05 06:56:40 +08:00
|
|
|
g_net2->bytesReceived += size;
|
|
|
|
//TraceEvent("ConnRead", this->id).detail("Bytes", size);
|
|
|
|
if (err) {
|
|
|
|
if (err == boost::asio::error::would_block) {
|
|
|
|
++g_net2->countWouldBlock;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
onReadError(err);
|
|
|
|
throw connection_failed();
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
ASSERT(size); // If the socket is closed, we expect an 'eof' error, not a zero return value
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// Writes as many bytes as possible from the given SendBuffer chain into the write buffer and returns the number of
|
|
|
|
// bytes written (might be 0)
|
|
|
|
int write(SendBuffer const* data, int limit) override {
|
2020-06-04 16:32:12 +08:00
|
|
|
#ifdef __APPLE__
|
2021-03-11 02:06:03 +08:00
|
|
|
// For some reason, writing ssl_sock with more than 2016 bytes when socket is writeable sometimes results in a
|
|
|
|
// broken pipe error.
|
2020-06-04 16:32:12 +08:00
|
|
|
limit = std::min(limit, 2016);
|
|
|
|
#endif
|
2020-02-05 06:56:40 +08:00
|
|
|
boost::system::error_code err;
|
|
|
|
++g_net2->countWrites;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
size_t sent = ssl_sock.write_some(
|
|
|
|
boost::iterator_range<SendBufferIterator>(SendBufferIterator(data, limit), SendBufferIterator()), err);
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
if (err) {
|
2021-03-11 02:06:03 +08:00
|
|
|
// Since there was an error, sent's value can't be used to infer that the buffer has data and the limit is
|
|
|
|
// positive so check explicitly.
|
2020-02-05 06:56:40 +08:00
|
|
|
ASSERT(limit > 0);
|
|
|
|
bool notEmpty = false;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (auto p = data; p; p = p->next)
|
|
|
|
if (p->bytes_written - p->bytes_sent > 0) {
|
2020-02-05 06:56:40 +08:00
|
|
|
notEmpty = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ASSERT(notEmpty);
|
|
|
|
|
|
|
|
if (err == boost::asio::error::would_block) {
|
|
|
|
++g_net2->countWouldBlock;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
onWriteError(err);
|
|
|
|
throw connection_failed();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ASSERT(sent); // Make sure data was sent, and also this check will fail if the buffer chain was empty or the
|
|
|
|
// limit was not > 0.
|
2020-02-05 06:56:40 +08:00
|
|
|
return sent;
|
|
|
|
}
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
NetworkAddress getPeerAddress() const override { return peer_address; }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
UID getDebugID() const override { return id; }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
tcp::socket& getSocket() { return socket; }
|
|
|
|
|
|
|
|
ssl_socket& getSSLSocket() { return ssl_sock; }
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2020-02-05 06:56:40 +08:00
|
|
|
private:
|
|
|
|
UID id;
|
|
|
|
tcp::socket socket;
|
|
|
|
ssl_socket ssl_sock;
|
|
|
|
NetworkAddress peer_address;
|
2020-03-06 09:25:33 +08:00
|
|
|
Reference<ReferencedObject<boost::asio::ssl::context>> sslContext;
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
void init() {
|
|
|
|
// Socket settings that have to be set after connect or accept succeeds
|
|
|
|
socket.non_blocking(true);
|
|
|
|
socket.set_option(boost::asio::ip::tcp::no_delay(true));
|
|
|
|
platform::setCloseOnExec(socket.native_handle());
|
|
|
|
}
|
|
|
|
|
|
|
|
void closeSocket() {
|
2020-02-21 10:17:39 +08:00
|
|
|
boost::system::error_code cancelError;
|
|
|
|
socket.cancel(cancelError);
|
|
|
|
boost::system::error_code closeError;
|
|
|
|
socket.close(closeError);
|
|
|
|
boost::system::error_code shutdownError;
|
|
|
|
ssl_sock.shutdown(shutdownError);
|
2020-02-05 06:56:40 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void onReadError(const boost::system::error_code& error) {
|
|
|
|
TraceEvent(SevWarn, "N2_ReadError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
2020-02-05 06:56:40 +08:00
|
|
|
closeSocket();
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
void onWriteError(const boost::system::error_code& error) {
|
|
|
|
TraceEvent(SevWarn, "N2_WriteError", id)
|
|
|
|
.suppressFor(1.0)
|
|
|
|
.detail("ErrorCode", error.value())
|
|
|
|
.detail("Message", error.message());
|
2020-02-05 06:56:40 +08:00
|
|
|
closeSocket();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
class SSLListener final : public IListener, ReferenceCounted<SSLListener> {
|
2020-03-05 06:26:01 +08:00
|
|
|
boost::asio::io_context& io_service;
|
2020-02-05 06:56:40 +08:00
|
|
|
NetworkAddress listenAddress;
|
|
|
|
tcp::acceptor acceptor;
|
2021-03-11 02:06:03 +08:00
|
|
|
AsyncVar<Reference<ReferencedObject<boost::asio::ssl::context>>>* contextVar;
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
public:
|
2021-03-11 02:06:03 +08:00
|
|
|
SSLListener(boost::asio::io_context& io_service,
|
|
|
|
AsyncVar<Reference<ReferencedObject<boost::asio::ssl::context>>>* contextVar,
|
|
|
|
NetworkAddress listenAddress)
|
|
|
|
: io_service(io_service), listenAddress(listenAddress), acceptor(io_service, tcpEndpoint(listenAddress)),
|
|
|
|
contextVar(contextVar) {
|
2020-02-05 06:56:40 +08:00
|
|
|
platform::setCloseOnExec(acceptor.native_handle());
|
|
|
|
}
|
|
|
|
|
2020-11-28 02:10:41 +08:00
|
|
|
void addref() override { ReferenceCounted<SSLListener>::addref(); }
|
|
|
|
void delref() override { ReferenceCounted<SSLListener>::delref(); }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
// Returns one incoming connection when it is available
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Reference<IConnection>> accept() override { return doAccept(this); }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2020-11-23 12:09:10 +08:00
|
|
|
NetworkAddress getListenAddress() const override { return listenAddress; }
|
2020-02-05 06:56:40 +08:00
|
|
|
|
|
|
|
private:
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Reference<IConnection>> doAccept(SSLListener* self) {
|
|
|
|
state Reference<SSLConnection> conn(new SSLConnection(self->io_service, self->contextVar->get()));
|
2020-02-05 06:56:40 +08:00
|
|
|
state tcp::acceptor::endpoint_type peer_endpoint;
|
|
|
|
try {
|
|
|
|
BindPromise p("N2_AcceptError", UID());
|
|
|
|
auto f = p.getFuture();
|
2021-03-11 02:06:03 +08:00
|
|
|
self->acceptor.async_accept(conn->getSocket(), peer_endpoint, std::move(p));
|
|
|
|
wait(f);
|
|
|
|
auto peer_address = peer_endpoint.address().is_v6() ? IPAddress(peer_endpoint.address().to_v6().to_bytes())
|
|
|
|
: IPAddress(peer_endpoint.address().to_v4().to_ulong());
|
|
|
|
|
2020-02-05 06:56:40 +08:00
|
|
|
conn->accept(NetworkAddress(peer_address, peer_endpoint.port(), false, true));
|
|
|
|
|
|
|
|
return conn;
|
|
|
|
} catch (...) {
|
|
|
|
conn->close();
|
2020-02-07 08:45:54 +08:00
|
|
|
throw;
|
2020-02-05 06:56:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2020-02-20 10:37:47 +08:00
|
|
|
#endif
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2021-07-22 13:43:04 +08:00
|
|
|
struct PromiseTask final : public Task, public FastAllocated<PromiseTask> {
|
2017-05-26 04:48:44 +08:00
|
|
|
Promise<Void> promise;
|
|
|
|
PromiseTask() {}
|
2020-06-10 08:33:41 +08:00
|
|
|
explicit PromiseTask(Promise<Void>&& promise) noexcept : promise(std::move(promise)) {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-01-26 09:55:43 +08:00
|
|
|
void operator()() override {
|
2017-05-26 04:48:44 +08:00
|
|
|
promise.send(Void());
|
|
|
|
delete this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-02-19 16:57:05 +08:00
|
|
|
// 5MB for loading files into memory
|
|
|
|
|
2020-03-05 12:14:47 +08:00
|
|
|
Net2::Net2(const TLSConfig& tlsConfig, bool useThreadPool, bool useMetrics)
|
2021-11-18 07:25:36 +08:00
|
|
|
: globals(enumGlobal::COUNT), useThreadPool(useThreadPool), reactor(this),
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
2021-03-11 02:06:03 +08:00
|
|
|
sslContextVar({ ReferencedObject<boost::asio::ssl::context>::from(
|
|
|
|
boost::asio::ssl::context(boost::asio::ssl::context::tls)) }),
|
2021-07-25 02:20:51 +08:00
|
|
|
sslHandshakerThreadsStarted(0), sslPoolHandshakesInProgress(0),
|
2020-02-20 10:37:47 +08:00
|
|
|
#endif
|
2021-07-25 08:29:27 +08:00
|
|
|
tlsConfig(tlsConfig), tlsInitializedState(ETLSInitState::NONE), network(this), tscBegin(0), tscEnd(0), taskBegin(0),
|
2021-07-25 02:20:51 +08:00
|
|
|
currentTaskID(TaskPriority::DefaultYield), tasksIssued(0), stopped(false), started(false), numYields(0),
|
2021-07-25 08:29:27 +08:00
|
|
|
lastPriorityStats(nullptr), ready(FLOW_KNOBS->READY_QUEUE_RESERVED_SIZE) {
|
2021-07-25 02:20:51 +08:00
|
|
|
// Until run() is called, yield() will always yield
|
2021-07-27 10:55:10 +08:00
|
|
|
TraceEvent("Net2Starting").log();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
// Set the global members
|
2021-03-11 02:06:03 +08:00
|
|
|
if (useMetrics) {
|
|
|
|
setGlobal(INetwork::enTDMetrics, (flowGlobalType)&tdmetrics);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2021-07-29 07:03:37 +08:00
|
|
|
if (FLOW_KNOBS->ENABLE_CHAOS_FEATURES) {
|
|
|
|
setGlobal(INetwork::enChaosMetrics, (flowGlobalType)&chaosMetrics);
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
setGlobal(INetwork::enNetworkConnections, (flowGlobalType)network);
|
|
|
|
setGlobal(INetwork::enASIOService, (flowGlobalType)&reactor.ios);
|
2017-12-21 17:58:15 +08:00
|
|
|
setGlobal(INetwork::enBlobCredentialFiles, &blobCredentialFiles);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
#ifdef __linux__
|
2021-03-11 02:06:03 +08:00
|
|
|
setGlobal(INetwork::enEventFD, (flowGlobalType)N2::ASIOReactor::newEventFD(reactor));
|
2017-05-26 04:48:44 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
updateNow();
|
|
|
|
}
|
|
|
|
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Void> watchFileForChanges(std::string filename, AsyncTrigger* fileChanged) {
|
2020-03-06 09:25:33 +08:00
|
|
|
if (filename == "") {
|
|
|
|
return Never();
|
|
|
|
}
|
2020-04-21 12:38:04 +08:00
|
|
|
state bool firstRun = true;
|
|
|
|
state bool statError = false;
|
|
|
|
state std::time_t lastModTime = 0;
|
2020-03-05 12:14:47 +08:00
|
|
|
loop {
|
2020-03-06 18:33:16 +08:00
|
|
|
try {
|
|
|
|
std::time_t modtime = wait(IAsyncFileSystem::filesystem()->lastWriteTime(filename));
|
2020-04-21 12:38:04 +08:00
|
|
|
if (firstRun) {
|
|
|
|
lastModTime = modtime;
|
|
|
|
firstRun = false;
|
|
|
|
}
|
|
|
|
if (lastModTime != modtime || statError) {
|
2020-03-06 18:33:16 +08:00
|
|
|
lastModTime = modtime;
|
2020-04-21 12:38:04 +08:00
|
|
|
statError = false;
|
2020-03-06 18:33:16 +08:00
|
|
|
fileChanged->trigger();
|
2020-02-27 08:06:45 +08:00
|
|
|
}
|
2020-03-06 18:33:16 +08:00
|
|
|
} catch (Error& e) {
|
|
|
|
if (e.code() == error_code_io_error) {
|
|
|
|
// EACCES, ELOOP, ENOENT all come out as io_error(), but are more of a system
|
|
|
|
// configuration issue than an FDB problem. If we managed to load valid
|
|
|
|
// certificates, then there's no point in crashing, but we should complain
|
|
|
|
// loudly. IAsyncFile will log the error, but not necessarily as a warning.
|
|
|
|
TraceEvent(SevWarnAlways, "TLSCertificateRefreshStatError").detail("File", filename);
|
2020-04-21 12:38:04 +08:00
|
|
|
statError = true;
|
2020-03-06 18:33:16 +08:00
|
|
|
} else {
|
|
|
|
throw;
|
2020-02-27 08:06:45 +08:00
|
|
|
}
|
2020-02-27 07:33:48 +08:00
|
|
|
}
|
2020-04-21 12:38:04 +08:00
|
|
|
wait(delay(FLOW_KNOBS->TLS_CERT_REFRESH_DELAY_SECONDS));
|
2020-03-05 12:14:47 +08:00
|
|
|
}
|
|
|
|
}
|
2020-02-27 07:33:48 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<Void> reloadCertificatesOnChange(
|
|
|
|
TLSConfig config,
|
|
|
|
std::function<void()> onPolicyFailure,
|
|
|
|
AsyncVar<Reference<ReferencedObject<boost::asio::ssl::context>>>* contextVar) {
|
2020-03-06 09:25:33 +08:00
|
|
|
if (FLOW_KNOBS->TLS_CERT_REFRESH_DELAY_SECONDS <= 0) {
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
loop {
|
|
|
|
// Early in bootup, the filesystem might not be initialized yet. Wait until it is.
|
|
|
|
if (IAsyncFileSystem::filesystem() != nullptr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
wait(delay(1.0));
|
|
|
|
}
|
|
|
|
state int mismatches = 0;
|
|
|
|
state AsyncTrigger fileChanged;
|
|
|
|
state std::vector<Future<Void>> lifetimes;
|
|
|
|
lifetimes.push_back(watchFileForChanges(config.getCertificatePathSync(), &fileChanged));
|
|
|
|
lifetimes.push_back(watchFileForChanges(config.getKeyPathSync(), &fileChanged));
|
|
|
|
lifetimes.push_back(watchFileForChanges(config.getCAPathSync(), &fileChanged));
|
|
|
|
loop {
|
2021-03-11 02:06:03 +08:00
|
|
|
wait(fileChanged.onTrigger());
|
2021-07-27 10:55:10 +08:00
|
|
|
TraceEvent("TLSCertificateRefreshBegin").log();
|
2020-03-06 09:25:33 +08:00
|
|
|
|
|
|
|
try {
|
2021-03-11 02:06:03 +08:00
|
|
|
LoadedTLSConfig loaded = wait(config.loadAsync());
|
2020-03-06 09:25:33 +08:00
|
|
|
boost::asio::ssl::context context(boost::asio::ssl::context::tls);
|
2020-03-13 17:24:37 +08:00
|
|
|
ConfigureSSLContext(loaded, &context, onPolicyFailure);
|
2021-07-27 10:55:10 +08:00
|
|
|
TraceEvent(SevInfo, "TLSCertificateRefreshSucceeded").log();
|
2020-03-06 09:25:33 +08:00
|
|
|
mismatches = 0;
|
|
|
|
contextVar->set(ReferencedObject<boost::asio::ssl::context>::from(std::move(context)));
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2020-03-07 03:09:17 +08:00
|
|
|
if (e.code() == error_code_actor_cancelled) {
|
|
|
|
throw;
|
2020-02-27 10:02:56 +08:00
|
|
|
}
|
2020-03-06 09:25:33 +08:00
|
|
|
// Some files didn't match up, they should in the future, and we'll retry then.
|
|
|
|
mismatches++;
|
2020-03-06 18:33:16 +08:00
|
|
|
TraceEvent(SevWarn, "TLSCertificateRefreshMismatch").error(e).detail("mismatches", mismatches);
|
2020-02-27 07:33:48 +08:00
|
|
|
}
|
2020-03-06 09:25:33 +08:00
|
|
|
}
|
2020-03-05 12:14:47 +08:00
|
|
|
}
|
2020-03-06 09:32:10 +08:00
|
|
|
#endif
|
2020-03-05 12:14:47 +08:00
|
|
|
|
2020-06-29 08:29:13 +08:00
|
|
|
void Net2::initTLS(ETLSInitState targetState) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (tlsInitializedState >= targetState) {
|
2020-02-27 09:50:07 +08:00
|
|
|
return;
|
|
|
|
}
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
2020-06-29 08:29:13 +08:00
|
|
|
// Any target state must be higher than NONE so if the current state is NONE
|
|
|
|
// then initialize the TLS config
|
2021-03-11 02:06:03 +08:00
|
|
|
if (tlsInitializedState == ETLSInitState::NONE) {
|
2020-06-29 08:29:13 +08:00
|
|
|
auto onPolicyFailure = [this]() { this->countTLSPolicyFailures++; };
|
|
|
|
try {
|
|
|
|
boost::asio::ssl::context newContext(boost::asio::ssl::context::tls);
|
|
|
|
const LoadedTLSConfig& loaded = tlsConfig.loadSync();
|
|
|
|
TraceEvent("Net2TLSConfig")
|
2021-03-11 02:06:03 +08:00
|
|
|
.detail("CAPath", tlsConfig.getCAPathSync())
|
|
|
|
.detail("CertificatePath", tlsConfig.getCertificatePathSync())
|
|
|
|
.detail("KeyPath", tlsConfig.getKeyPathSync())
|
|
|
|
.detail("HasPassword", !loaded.getPassword().empty())
|
|
|
|
.detail("VerifyPeers", boost::algorithm::join(loaded.getVerifyPeers(), "|"));
|
|
|
|
ConfigureSSLContext(tlsConfig.loadSync(), &newContext, onPolicyFailure);
|
2020-06-29 08:29:13 +08:00
|
|
|
sslContextVar.set(ReferencedObject<boost::asio::ssl::context>::from(std::move(newContext)));
|
|
|
|
} catch (Error& e) {
|
|
|
|
TraceEvent("Net2TLSInitError").error(e);
|
2020-06-23 18:09:56 +08:00
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
backgroundCertRefresh = reloadCertificatesOnChange(tlsConfig, onPolicyFailure, &sslContextVar);
|
2020-06-29 08:29:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// If a TLS connection is actually going to be used then start background threads if configured
|
2021-03-11 02:06:03 +08:00
|
|
|
if (targetState > ETLSInitState::CONFIG) {
|
2020-06-29 08:29:13 +08:00
|
|
|
int threadsToStart;
|
2021-03-11 02:06:03 +08:00
|
|
|
switch (targetState) {
|
|
|
|
case ETLSInitState::CONNECT:
|
|
|
|
threadsToStart = FLOW_KNOBS->TLS_CLIENT_HANDSHAKE_THREADS;
|
|
|
|
break;
|
|
|
|
case ETLSInitState::LISTEN:
|
|
|
|
threadsToStart = FLOW_KNOBS->TLS_SERVER_HANDSHAKE_THREADS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
threadsToStart = 0;
|
2020-06-29 08:29:13 +08:00
|
|
|
};
|
|
|
|
threadsToStart -= sslHandshakerThreadsStarted;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (threadsToStart > 0) {
|
|
|
|
if (sslHandshakerThreadsStarted == 0) {
|
|
|
|
#if defined(__linux__)
|
|
|
|
if (mallopt(M_ARENA_MAX, FLOW_KNOBS->TLS_MALLOC_ARENA_MAX) != 1) {
|
|
|
|
TraceEvent(SevWarn, "TLSMallocSetMaxArenasFailure")
|
|
|
|
.detail("MaxArenas", FLOW_KNOBS->TLS_MALLOC_ARENA_MAX);
|
2020-06-29 08:29:13 +08:00
|
|
|
};
|
2021-03-11 02:06:03 +08:00
|
|
|
#endif
|
2020-06-29 08:29:13 +08:00
|
|
|
sslHandshakerPool = createGenericThreadPool(FLOW_KNOBS->TLS_HANDSHAKE_THREAD_STACKSIZE);
|
|
|
|
}
|
2020-06-23 18:09:56 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
for (int i = 0; i < threadsToStart; ++i) {
|
2020-06-29 08:29:13 +08:00
|
|
|
++sslHandshakerThreadsStarted;
|
2022-01-25 10:00:00 +08:00
|
|
|
sslHandshakerPool->addThread(new SSLHandshakerThread(), "fdb-ssl-connect");
|
2020-06-29 08:29:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-02-20 10:37:47 +08:00
|
|
|
#endif
|
2020-06-29 08:29:13 +08:00
|
|
|
|
|
|
|
tlsInitializedState = targetState;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ACTOR Future<Void> Net2::logTimeOffset() {
|
|
|
|
loop {
|
|
|
|
double processTime = timer_monotonic();
|
|
|
|
double systemTime = timer();
|
2021-03-11 02:06:03 +08:00
|
|
|
TraceEvent("ProcessTimeOffset")
|
|
|
|
.detailf("ProcessTime", "%lf", processTime)
|
|
|
|
.detailf("SystemTime", "%lf", systemTime)
|
|
|
|
.detailf("OffsetFromSystemTime", "%lf", processTime - systemTime);
|
2018-08-11 04:57:10 +08:00
|
|
|
wait(::delay(FLOW_KNOBS->TIME_OFFSET_LOGGING_INTERVAL));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Net2::initMetrics() {
|
|
|
|
bytesReceived.init(LiteralStringRef("Net2.BytesReceived"));
|
|
|
|
countWriteProbes.init(LiteralStringRef("Net2.CountWriteProbes"));
|
|
|
|
countReadProbes.init(LiteralStringRef("Net2.CountReadProbes"));
|
|
|
|
countReads.init(LiteralStringRef("Net2.CountReads"));
|
|
|
|
countWouldBlock.init(LiteralStringRef("Net2.CountWouldBlock"));
|
|
|
|
countWrites.init(LiteralStringRef("Net2.CountWrites"));
|
|
|
|
countRunLoop.init(LiteralStringRef("Net2.CountRunLoop"));
|
|
|
|
countCantSleep.init(LiteralStringRef("Net2.CountCantSleep"));
|
|
|
|
countWontSleep.init(LiteralStringRef("Net2.CountWontSleep"));
|
|
|
|
countTimers.init(LiteralStringRef("Net2.CountTimers"));
|
|
|
|
countTasks.init(LiteralStringRef("Net2.CountTasks"));
|
|
|
|
countYields.init(LiteralStringRef("Net2.CountYields"));
|
|
|
|
countYieldBigStack.init(LiteralStringRef("Net2.CountYieldBigStack"));
|
|
|
|
countYieldCalls.init(LiteralStringRef("Net2.CountYieldCalls"));
|
|
|
|
countASIOEvents.init(LiteralStringRef("Net2.CountASIOEvents"));
|
|
|
|
countYieldCallsTrue.init(LiteralStringRef("Net2.CountYieldCallsTrue"));
|
2020-01-29 04:09:37 +08:00
|
|
|
countRunLoopProfilingSignals.init(LiteralStringRef("Net2.CountRunLoopProfilingSignals"));
|
2020-03-13 17:24:37 +08:00
|
|
|
countTLSPolicyFailures.init(LiteralStringRef("Net2.CountTLSPolicyFailures"));
|
2017-05-26 04:48:44 +08:00
|
|
|
priorityMetric.init(LiteralStringRef("Net2.Priority"));
|
|
|
|
awakeMetric.init(LiteralStringRef("Net2.Awake"));
|
|
|
|
slowTaskMetric.init(LiteralStringRef("Net2.SlowTask"));
|
2019-08-29 05:35:48 +08:00
|
|
|
countLaunchTime.init(LiteralStringRef("Net2.CountLaunchTime"));
|
|
|
|
countReactTime.init(LiteralStringRef("Net2.CountReactTime"));
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2020-05-23 04:31:06 +08:00
|
|
|
bool Net2::checkRunnable() {
|
|
|
|
return !started.exchange(true);
|
|
|
|
}
|
|
|
|
|
2021-07-24 08:18:13 +08:00
|
|
|
#ifdef ENABLE_SAMPLING
|
2021-06-04 06:10:04 +08:00
|
|
|
ActorLineageSet& Net2::getActorLineageSet() {
|
|
|
|
return actorLineageSet;
|
|
|
|
}
|
2021-07-24 08:18:13 +08:00
|
|
|
#endif
|
2021-06-04 06:10:04 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
void Net2::run() {
|
|
|
|
TraceEvent::setNetworkThread();
|
2021-07-27 10:55:10 +08:00
|
|
|
TraceEvent("Net2Running").log();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
thread_network = this;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
if (timeBeginPeriod(1) != TIMERR_NOERROR)
|
2021-07-27 10:55:10 +08:00
|
|
|
TraceEvent(SevError, "TimeBeginPeriodError").log();
|
2017-05-26 04:48:44 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
timeOffsetLogger = logTimeOffset();
|
2021-03-11 02:06:03 +08:00
|
|
|
const char* flow_profiler_enabled = getenv("FLOW_PROFILER_ENABLED");
|
2017-10-12 05:13:16 +08:00
|
|
|
if (flow_profiler_enabled != nullptr && *flow_profiler_enabled != '\0') {
|
2021-03-11 02:06:03 +08:00
|
|
|
// The empty string check is to allow running `FLOW_PROFILER_ENABLED= ./fdbserver` to force disabling flow
|
|
|
|
// profiling at startup.
|
2017-10-12 05:13:16 +08:00
|
|
|
startProfiling(this);
|
|
|
|
}
|
2017-06-27 06:54:57 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
// Get the address to the launch function
|
|
|
|
typedef void (*runCycleFuncPtr)();
|
2021-03-11 02:06:03 +08:00
|
|
|
runCycleFuncPtr runFunc = reinterpret_cast<runCycleFuncPtr>(
|
|
|
|
reinterpret_cast<flowGlobalType>(g_network->global(INetwork::enRunCycleFunc)));
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-05-23 04:31:06 +08:00
|
|
|
started.store(true);
|
2017-05-26 04:48:44 +08:00
|
|
|
double nnow = timer_monotonic();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
while (!stopped) {
|
2019-05-30 06:12:10 +08:00
|
|
|
FDB_TRACE_PROBE(run_loop_begin);
|
2017-05-26 04:48:44 +08:00
|
|
|
++countRunLoop;
|
|
|
|
|
|
|
|
if (runFunc) {
|
2020-04-15 10:22:37 +08:00
|
|
|
tscBegin = timestampCounter();
|
2019-06-27 05:03:02 +08:00
|
|
|
taskBegin = nnow;
|
2020-02-08 06:34:24 +08:00
|
|
|
trackAtPriority(TaskPriority::RunCycleFunction, taskBegin);
|
2017-05-26 04:48:44 +08:00
|
|
|
runFunc();
|
2019-08-29 05:35:48 +08:00
|
|
|
double taskEnd = timer_monotonic();
|
2020-02-08 06:34:24 +08:00
|
|
|
trackAtPriority(TaskPriority::RunLoop, taskEnd);
|
2019-08-29 05:35:48 +08:00
|
|
|
countLaunchTime += taskEnd - taskBegin;
|
2020-04-15 10:22:37 +08:00
|
|
|
checkForSlowTask(tscBegin, timestampCounter(), taskEnd - taskBegin, TaskPriority::RunCycleFunction);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
double sleepTime = 0;
|
|
|
|
bool b = ready.empty();
|
|
|
|
if (b) {
|
|
|
|
b = threadReady.canSleep();
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!b)
|
|
|
|
++countCantSleep;
|
2017-05-26 04:48:44 +08:00
|
|
|
} else
|
|
|
|
++countWontSleep;
|
|
|
|
if (b) {
|
|
|
|
sleepTime = 1e99;
|
2019-06-27 05:03:02 +08:00
|
|
|
double sleepStart = timer_monotonic();
|
|
|
|
if (!timers.empty()) {
|
2021-03-11 02:06:03 +08:00
|
|
|
sleepTime = timers.top().at - sleepStart; // + 500e-6?
|
2019-06-27 05:03:02 +08:00
|
|
|
}
|
2019-08-29 05:35:48 +08:00
|
|
|
if (sleepTime > 0) {
|
2020-01-29 04:09:37 +08:00
|
|
|
#if defined(__linux__)
|
|
|
|
// notify the run loop monitoring thread that we have gone idle
|
|
|
|
net2RunLoopSleeps.fetch_add(1);
|
|
|
|
#endif
|
|
|
|
|
2020-02-08 06:34:24 +08:00
|
|
|
trackAtPriority(TaskPriority::Zero, sleepStart);
|
2019-08-29 05:35:48 +08:00
|
|
|
awakeMetric = false;
|
|
|
|
priorityMetric = 0;
|
|
|
|
reactor.sleep(sleepTime);
|
|
|
|
awakeMetric = true;
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2020-04-15 10:22:37 +08:00
|
|
|
tscBegin = timestampCounter();
|
2019-08-29 05:35:48 +08:00
|
|
|
taskBegin = timer_monotonic();
|
2020-02-08 06:34:24 +08:00
|
|
|
trackAtPriority(TaskPriority::ASIOReactor, taskBegin);
|
2019-08-29 05:35:48 +08:00
|
|
|
reactor.react();
|
2021-03-11 02:06:03 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
updateNow();
|
|
|
|
double now = this->currentTime;
|
2020-02-08 06:34:24 +08:00
|
|
|
trackAtPriority(TaskPriority::RunLoop, now);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2019-08-29 05:35:48 +08:00
|
|
|
countReactTime += now - taskBegin;
|
2020-04-15 10:22:37 +08:00
|
|
|
checkForSlowTask(tscBegin, timestampCounter(), now - taskBegin, TaskPriority::ASIOReactor);
|
2019-08-29 05:35:48 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if ((now - nnow) > FLOW_KNOBS->SLOW_LOOP_CUTOFF &&
|
|
|
|
nondeterministicRandom()->random01() < (now - nnow) * FLOW_KNOBS->SLOW_LOOP_SAMPLING_RATE)
|
2017-05-26 04:48:44 +08:00
|
|
|
TraceEvent("SomewhatSlowRunLoopTop").detail("Elapsed", now - nnow);
|
|
|
|
|
2019-05-30 06:12:10 +08:00
|
|
|
int numTimers = 0;
|
2017-05-26 04:48:44 +08:00
|
|
|
while (!timers.empty() && timers.top().at < now) {
|
2019-05-30 06:12:10 +08:00
|
|
|
++numTimers;
|
2017-05-26 04:48:44 +08:00
|
|
|
++countTimers;
|
2021-03-11 02:06:03 +08:00
|
|
|
ready.push(timers.top());
|
2017-05-26 04:48:44 +08:00
|
|
|
timers.pop();
|
|
|
|
}
|
2022-01-02 12:04:00 +08:00
|
|
|
// FIXME: Is this double counting?
|
2019-05-30 06:12:10 +08:00
|
|
|
countTimers += numTimers;
|
|
|
|
FDB_TRACE_PROBE(run_loop_ready_timers, numTimers);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
processThreadReady();
|
|
|
|
|
2020-04-15 10:22:37 +08:00
|
|
|
tscBegin = timestampCounter();
|
2020-02-08 02:35:09 +08:00
|
|
|
tscEnd = tscBegin + FLOW_KNOBS->TSC_YIELD_TIME;
|
2017-05-26 04:48:44 +08:00
|
|
|
taskBegin = timer_monotonic();
|
|
|
|
numYields = 0;
|
2019-06-25 17:47:35 +08:00
|
|
|
TaskPriority minTaskID = TaskPriority::Max;
|
2021-12-02 10:13:17 +08:00
|
|
|
[[maybe_unused]] int queueSize = ready.size();
|
2017-06-27 06:54:57 +08:00
|
|
|
|
2019-05-30 06:12:10 +08:00
|
|
|
FDB_TRACE_PROBE(run_loop_tasks_start, queueSize);
|
2017-05-26 04:48:44 +08:00
|
|
|
while (!ready.empty()) {
|
|
|
|
++countTasks;
|
|
|
|
currentTaskID = ready.top().taskID;
|
2019-06-25 17:47:35 +08:00
|
|
|
priorityMetric = static_cast<int64_t>(currentTaskID);
|
2017-05-26 04:48:44 +08:00
|
|
|
Task* task = ready.top().task;
|
|
|
|
ready.pop();
|
|
|
|
|
|
|
|
try {
|
|
|
|
(*task)();
|
|
|
|
} catch (Error& e) {
|
|
|
|
TraceEvent(SevError, "TaskError").error(e);
|
|
|
|
} catch (...) {
|
|
|
|
TraceEvent(SevError, "TaskError").error(unknown_error());
|
|
|
|
}
|
|
|
|
|
2021-03-12 03:34:07 +08:00
|
|
|
if (currentTaskID < minTaskID) {
|
|
|
|
trackAtPriority(currentTaskID, taskBegin);
|
|
|
|
minTaskID = currentTaskID;
|
|
|
|
}
|
|
|
|
|
2022-01-02 12:14:57 +08:00
|
|
|
// attempt to empty out the IO backlog
|
|
|
|
if (ready.size() % FLOW_KNOBS->ITERATIONS_PER_REACTOR_CHECK == 1) {
|
2021-12-17 05:20:22 +08:00
|
|
|
if (runFunc) {
|
|
|
|
runFunc();
|
|
|
|
}
|
|
|
|
reactor.react();
|
|
|
|
}
|
2021-12-16 06:40:20 +08:00
|
|
|
|
2020-04-15 10:22:37 +08:00
|
|
|
double tscNow = timestampCounter();
|
2020-02-08 02:35:09 +08:00
|
|
|
double newTaskBegin = timer_monotonic();
|
|
|
|
if (check_yield(TaskPriority::Max, tscNow)) {
|
|
|
|
checkForSlowTask(tscBegin, tscNow, newTaskBegin - taskBegin, currentTaskID);
|
2021-07-29 07:03:37 +08:00
|
|
|
taskBegin = newTaskBegin;
|
2019-05-30 06:12:10 +08:00
|
|
|
FDB_TRACE_PROBE(run_loop_yield);
|
|
|
|
++countYields;
|
2020-01-16 07:51:15 +08:00
|
|
|
break;
|
2019-05-22 04:35:27 +08:00
|
|
|
}
|
2020-02-08 02:35:09 +08:00
|
|
|
|
|
|
|
taskBegin = newTaskBegin;
|
|
|
|
tscBegin = tscNow;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2020-01-16 07:51:15 +08:00
|
|
|
|
2020-02-08 06:34:24 +08:00
|
|
|
trackAtPriority(TaskPriority::RunLoop, taskBegin);
|
2020-01-16 07:51:15 +08:00
|
|
|
|
2019-05-22 04:35:27 +08:00
|
|
|
queueSize = ready.size();
|
2019-05-30 06:12:10 +08:00
|
|
|
FDB_TRACE_PROBE(run_loop_done, queueSize);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
#if defined(__linux__)
|
2021-03-11 02:06:03 +08:00
|
|
|
if (FLOW_KNOBS->RUN_LOOP_PROFILING_INTERVAL > 0) {
|
2017-05-26 04:48:44 +08:00
|
|
|
sigset_t orig_set;
|
|
|
|
pthread_sigmask(SIG_BLOCK, &sigprof_set, &orig_set);
|
|
|
|
|
|
|
|
size_t other_offset = net2backtraces_offset;
|
|
|
|
bool was_overflow = net2backtraces_overflow;
|
|
|
|
int signal_count = net2backtraces_count;
|
|
|
|
|
2020-01-29 04:09:37 +08:00
|
|
|
countRunLoopProfilingSignals += signal_count;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
if (other_offset) {
|
|
|
|
volatile void** _traces = net2backtraces;
|
|
|
|
net2backtraces = other_backtraces;
|
|
|
|
other_backtraces = _traces;
|
|
|
|
|
|
|
|
net2backtraces_offset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
net2backtraces_overflow = false;
|
|
|
|
net2backtraces_count = 0;
|
|
|
|
|
2020-08-28 06:31:24 +08:00
|
|
|
pthread_sigmask(SIG_SETMASK, &orig_set, nullptr);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
if (was_overflow) {
|
2020-01-29 04:09:37 +08:00
|
|
|
TraceEvent("Net2RunLoopProfilerOverflow")
|
2021-03-11 02:06:03 +08:00
|
|
|
.detail("SignalsReceived", signal_count)
|
|
|
|
.detail("BackTraceHarvested", other_offset != 0);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
if (other_offset) {
|
|
|
|
size_t iter_offset = 0;
|
|
|
|
while (iter_offset < other_offset) {
|
2021-03-11 02:06:03 +08:00
|
|
|
ProfilingSample* ps = (ProfilingSample*)(other_backtraces + iter_offset);
|
|
|
|
TraceEvent(SevWarn, "Net2RunLoopTrace")
|
|
|
|
.detailf("TraceTime", "%.6f", ps->timestamp)
|
|
|
|
.detail("Trace", platform::format_backtrace(ps->frames, ps->length));
|
2017-05-26 04:48:44 +08:00
|
|
|
iter_offset += ps->length + 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// notify the run loop monitoring thread that we are making progress
|
2020-01-29 04:09:37 +08:00
|
|
|
net2RunLoopIterations.fetch_add(1);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
#endif
|
2019-06-27 05:03:02 +08:00
|
|
|
nnow = timer_monotonic();
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if ((nnow - now) > FLOW_KNOBS->SLOW_LOOP_CUTOFF &&
|
|
|
|
nondeterministicRandom()->random01() < (nnow - now) * FLOW_KNOBS->SLOW_LOOP_SAMPLING_RATE)
|
|
|
|
TraceEvent("SomewhatSlowRunLoopBottom")
|
|
|
|
.detail("Elapsed", nnow - now); // This includes the time spent running tasks
|
2022-01-02 12:04:00 +08:00
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
for (auto& fn : stopCallbacks) {
|
2020-04-21 04:14:19 +08:00
|
|
|
fn();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
#ifdef WIN32
|
2017-05-26 04:48:44 +08:00
|
|
|
timeEndPeriod(1);
|
2021-03-11 02:06:03 +08:00
|
|
|
#endif
|
2021-12-16 06:40:20 +08:00
|
|
|
} // Net2::run
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-17 05:49:36 +08:00
|
|
|
// Updates the PriorityStats found in NetworkMetrics
|
2021-03-24 04:56:37 +08:00
|
|
|
void Net2::updateStarvationTracker(struct NetworkMetrics::PriorityStats& binStats,
|
2021-03-24 07:09:08 +08:00
|
|
|
TaskPriority priority,
|
|
|
|
TaskPriority lastPriority,
|
|
|
|
double now) {
|
2021-03-16 07:23:56 +08:00
|
|
|
|
|
|
|
// Busy -> idle at binStats.priority
|
|
|
|
if (binStats.priority > priority && binStats.priority <= lastPriority) {
|
|
|
|
binStats.active = false;
|
|
|
|
binStats.duration += now - binStats.windowedTimer;
|
|
|
|
binStats.maxDuration = std::max(binStats.maxDuration, now - binStats.timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Idle -> busy at binStats.priority
|
|
|
|
else if (binStats.priority <= priority && binStats.priority > lastPriority) {
|
|
|
|
binStats.active = true;
|
|
|
|
binStats.timer = now;
|
|
|
|
binStats.windowedTimer = now;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 04:56:37 +08:00
|
|
|
// Update both vectors of starvation trackers (one that updates every 5s and the other every 1s)
|
2021-03-11 02:06:03 +08:00
|
|
|
void Net2::trackAtPriority(TaskPriority priority, double now) {
|
2020-02-08 06:34:24 +08:00
|
|
|
if (lastPriorityStats == nullptr || priority != lastPriorityStats->priority) {
|
|
|
|
// Start tracking current priority
|
|
|
|
auto activeStatsItr = networkInfo.metrics.activeTrackers.try_emplace(priority, priority);
|
|
|
|
activeStatsItr.first->second.active = true;
|
|
|
|
activeStatsItr.first->second.windowedTimer = now;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (lastPriorityStats != nullptr) {
|
2020-02-08 06:34:24 +08:00
|
|
|
// Stop tracking previous priority
|
|
|
|
lastPriorityStats->active = false;
|
|
|
|
lastPriorityStats->duration += now - lastPriorityStats->windowedTimer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update starvation trackers
|
|
|
|
TaskPriority lastPriority = (lastPriorityStats == nullptr) ? TaskPriority::Zero : lastPriorityStats->priority;
|
2021-03-11 02:06:03 +08:00
|
|
|
for (auto& binStats : networkInfo.metrics.starvationTrackers) {
|
|
|
|
if (binStats.priority > lastPriority && binStats.priority > priority) {
|
2020-02-08 06:34:24 +08:00
|
|
|
break;
|
|
|
|
}
|
2021-03-24 04:56:37 +08:00
|
|
|
updateStarvationTracker(binStats, priority, lastPriority, now);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2019-06-27 05:03:02 +08:00
|
|
|
|
2021-03-17 07:29:02 +08:00
|
|
|
// Update starvation trackers for network busyness
|
2021-03-24 04:56:37 +08:00
|
|
|
updateStarvationTracker(networkInfo.metrics.starvationTrackerNetworkBusyness, priority, lastPriority, now);
|
2019-06-27 05:03:02 +08:00
|
|
|
|
2020-02-08 06:34:24 +08:00
|
|
|
lastPriorityStats = &activeStatsItr.first->second;
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Net2::processThreadReady() {
|
2019-05-30 06:12:10 +08:00
|
|
|
int numReady = 0;
|
2017-05-26 04:48:44 +08:00
|
|
|
while (true) {
|
|
|
|
Optional<OrderedTask> t = threadReady.pop();
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!t.present())
|
|
|
|
break;
|
2017-05-26 04:48:44 +08:00
|
|
|
t.get().priority -= ++tasksIssued;
|
2021-03-11 02:06:03 +08:00
|
|
|
ASSERT(t.get().task != 0);
|
|
|
|
ready.push(t.get());
|
2019-05-30 06:12:10 +08:00
|
|
|
++numReady;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
2019-05-30 06:12:10 +08:00
|
|
|
FDB_TRACE_PROBE(run_loop_thread_ready, numReady);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2019-06-25 17:47:35 +08:00
|
|
|
void Net2::checkForSlowTask(int64_t tscBegin, int64_t tscEnd, double duration, TaskPriority priority) {
|
2021-03-11 02:06:03 +08:00
|
|
|
int64_t elapsed = tscEnd - tscBegin;
|
2017-05-26 04:48:44 +08:00
|
|
|
if (elapsed > FLOW_KNOBS->TSC_YIELD_TIME && tscBegin > 0) {
|
2021-03-11 02:06:03 +08:00
|
|
|
int i = std::min<double>(NetworkMetrics::SLOW_EVENT_BINS - 1, log(elapsed / 1e6) / log(2.));
|
2020-01-13 08:44:30 +08:00
|
|
|
++networkInfo.metrics.countSlowEvents[i];
|
2019-03-16 01:34:57 +08:00
|
|
|
int64_t warnThreshold = g_network->isSimulated() ? 10e9 : 500e6;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
// printf("SlowTask: %d, %d yields\n", (int)(elapsed/1e6), numYields);
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
slowTaskMetric->clocks = elapsed;
|
2021-03-11 02:06:03 +08:00
|
|
|
slowTaskMetric->duration = (int64_t)(duration * 1e9);
|
2019-06-25 17:47:35 +08:00
|
|
|
slowTaskMetric->priority = static_cast<int64_t>(priority);
|
2017-05-26 04:48:44 +08:00
|
|
|
slowTaskMetric->numYields = numYields;
|
|
|
|
slowTaskMetric->log();
|
|
|
|
|
|
|
|
double sampleRate = std::min(1.0, (elapsed > warnThreshold) ? 1.0 : elapsed / 10e9);
|
2021-03-11 02:06:03 +08:00
|
|
|
double slowTaskProfilingLogInterval =
|
|
|
|
std::max(FLOW_KNOBS->RUN_LOOP_PROFILING_INTERVAL, FLOW_KNOBS->SLOWTASK_PROFILING_LOG_INTERVAL);
|
|
|
|
if (slowTaskProfilingLogInterval > 0 && duration > slowTaskProfilingLogInterval) {
|
2017-05-26 04:48:44 +08:00
|
|
|
sampleRate = 1; // Always include slow task events that could show up in our slow task profiling.
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (!DEBUG_DETERMINISM && (nondeterministicRandom()->random01() < sampleRate))
|
|
|
|
TraceEvent(elapsed > warnThreshold ? SevWarnAlways : SevInfo, "SlowTask")
|
|
|
|
.detail("TaskID", priority)
|
|
|
|
.detail("MClocks", elapsed / 1e6)
|
|
|
|
.detail("Duration", duration)
|
|
|
|
.detail("SampleRate", sampleRate)
|
|
|
|
.detail("NumYields", numYields);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
bool Net2::check_yield(TaskPriority taskID, int64_t tscNow) {
|
2020-01-16 07:51:15 +08:00
|
|
|
// SOMEDAY: Yield if there are lots of higher priority tasks queued?
|
2021-03-11 02:06:03 +08:00
|
|
|
if ((g_stackYieldLimit) && ((intptr_t)&taskID < g_stackYieldLimit)) {
|
2017-05-26 04:48:44 +08:00
|
|
|
++countYieldBigStack;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
processThreadReady();
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (taskID == TaskPriority::DefaultYield)
|
|
|
|
taskID = currentTaskID;
|
|
|
|
if (!ready.empty() && ready.top().priority > int64_t(taskID) << 32) {
|
2017-05-26 04:48:44 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-08 02:35:09 +08:00
|
|
|
if (tscNow < tscBegin) {
|
2017-05-26 04:48:44 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-02-08 02:35:09 +08:00
|
|
|
if (tscNow > tscEnd) {
|
2017-05-26 04:48:44 +08:00
|
|
|
++numYields;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
bool Net2::check_yield(TaskPriority taskID) {
|
|
|
|
if (numYields > 0) {
|
2020-02-08 02:35:09 +08:00
|
|
|
++numYields;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-04-15 10:22:37 +08:00
|
|
|
return check_yield(taskID, timestampCounter());
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<class Void> Net2::yield(TaskPriority taskID) {
|
2017-05-26 04:48:44 +08:00
|
|
|
++countYieldCalls;
|
2021-03-11 02:06:03 +08:00
|
|
|
if (taskID == TaskPriority::DefaultYield)
|
|
|
|
taskID = currentTaskID;
|
2020-02-08 02:35:09 +08:00
|
|
|
if (check_yield(taskID)) {
|
2017-05-26 04:48:44 +08:00
|
|
|
++countYieldCallsTrue;
|
|
|
|
return delay(0, taskID);
|
|
|
|
}
|
|
|
|
g_network->setCurrentTask(taskID);
|
|
|
|
return Void();
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Void> Net2::delay(double seconds, TaskPriority taskId) {
|
2017-05-26 04:48:44 +08:00
|
|
|
if (seconds <= 0.) {
|
|
|
|
PromiseTask* t = new PromiseTask;
|
2021-03-11 02:06:03 +08:00
|
|
|
this->ready.push(OrderedTask((int64_t(taskId) << 32) - (++tasksIssued), taskId, t));
|
2017-05-26 04:48:44 +08:00
|
|
|
return t->promise.getFuture();
|
|
|
|
}
|
2021-03-11 02:06:03 +08:00
|
|
|
if (seconds >=
|
|
|
|
4e12) // Intervals that overflow an int64_t in microseconds (more than 100,000 years) are treated as infinite
|
2017-05-26 04:48:44 +08:00
|
|
|
return Never();
|
|
|
|
|
|
|
|
double at = now() + seconds;
|
|
|
|
PromiseTask* t = new PromiseTask;
|
2021-03-11 02:06:03 +08:00
|
|
|
this->timers.push(DelayedTask(at, (int64_t(taskId) << 32) - (++tasksIssued), taskId, t));
|
2017-05-26 04:48:44 +08:00
|
|
|
return t->promise.getFuture();
|
|
|
|
}
|
|
|
|
|
2021-07-28 03:01:32 +08:00
|
|
|
Future<Void> Net2::orderedDelay(double seconds, TaskPriority taskId) {
|
|
|
|
// The regular delay already provides the required ordering property
|
|
|
|
return delay(seconds, taskId);
|
|
|
|
}
|
|
|
|
|
2019-06-25 17:47:35 +08:00
|
|
|
void Net2::onMainThread(Promise<Void>&& signal, TaskPriority taskID) {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (stopped)
|
|
|
|
return;
|
|
|
|
PromiseTask* p = new PromiseTask(std::move(signal));
|
|
|
|
int64_t priority = int64_t(taskID) << 32;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (thread_network == this) {
|
2018-07-17 07:10:24 +08:00
|
|
|
processThreadReady();
|
2021-03-11 02:06:03 +08:00
|
|
|
this->ready.push(OrderedTask(priority - (++tasksIssued), taskID, p));
|
2017-05-26 04:48:44 +08:00
|
|
|
} else {
|
2021-03-11 02:06:03 +08:00
|
|
|
if (threadReady.push(OrderedTask(priority, taskID, p)))
|
2017-05-26 04:48:44 +08:00
|
|
|
reactor.wake();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 06:51:01 +08:00
|
|
|
THREAD_HANDLE Net2::startThread(THREAD_FUNC_RETURN (*func)(void*), void* arg, int stackSize, const char* name) {
|
|
|
|
return ::startThread(func, arg, stackSize, name);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Reference<IConnection>> Net2::connect(NetworkAddress toAddr, const std::string& host) {
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
2021-03-11 02:06:03 +08:00
|
|
|
if (toAddr.isTLS()) {
|
2021-03-09 00:27:04 +08:00
|
|
|
initTLS(ETLSInitState::CONNECT);
|
2020-03-06 09:25:33 +08:00
|
|
|
return SSLConnection::connect(&this->reactor.ios, this->sslContextVar.get(), toAddr);
|
2020-02-05 06:56:40 +08:00
|
|
|
}
|
2020-02-20 10:37:47 +08:00
|
|
|
#endif
|
2020-02-05 06:56:40 +08:00
|
|
|
|
2017-05-26 04:48:44 +08:00
|
|
|
return Connection::connect(&this->reactor.ios, toAddr);
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Future<Reference<IConnection>> Net2::connectExternal(NetworkAddress toAddr, const std::string& host) {
|
2020-12-20 07:46:07 +08:00
|
|
|
return connect(toAddr, host);
|
|
|
|
}
|
|
|
|
|
2022-04-04 08:33:18 +08:00
|
|
|
Future<Reference<IUDPSocket>> Net2::createUDPSocket(NetworkAddress toAddr) {
|
|
|
|
return UDPSocket::connect(&reactor.ios, toAddr, toAddr.ip.isV6());
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<Reference<IUDPSocket>> Net2::createUDPSocket(bool isV6) {
|
|
|
|
return UDPSocket::connect(&reactor.ios, Optional<NetworkAddress>(), isV6);
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
ACTOR static Future<std::vector<NetworkAddress>> resolveTCPEndpoint_impl(Net2* self,
|
|
|
|
std::string host,
|
|
|
|
std::string service) {
|
2018-11-27 12:02:03 +08:00
|
|
|
state tcp::resolver tcpResolver(self->reactor.ios);
|
2018-11-27 11:53:46 +08:00
|
|
|
Promise<std::vector<NetworkAddress>> promise;
|
|
|
|
state Future<std::vector<NetworkAddress>> result = promise.getFuture();
|
2017-10-16 12:51:11 +08:00
|
|
|
|
2021-12-03 02:22:22 +08:00
|
|
|
tcpResolver.async_resolve(tcp::resolver::query(host, service),
|
|
|
|
[=](const boost::system::error_code& ec, tcp::resolver::iterator iter) {
|
|
|
|
if (ec) {
|
2022-04-04 08:33:18 +08:00
|
|
|
self->dnsCache.remove(host, service);
|
2021-12-03 02:22:22 +08:00
|
|
|
promise.sendError(lookup_failed());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<NetworkAddress> addrs;
|
|
|
|
|
|
|
|
tcp::resolver::iterator end;
|
|
|
|
while (iter != end) {
|
|
|
|
auto endpoint = iter->endpoint();
|
|
|
|
auto addr = endpoint.address();
|
|
|
|
if (addr.is_v6()) {
|
|
|
|
addrs.emplace_back(IPAddress(addr.to_v6().to_bytes()), endpoint.port());
|
|
|
|
} else {
|
2021-12-03 04:51:00 +08:00
|
|
|
addrs.emplace_back(addr.to_v4().to_ulong(), endpoint.port());
|
2021-12-03 02:22:22 +08:00
|
|
|
}
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addrs.empty()) {
|
2022-04-04 08:33:18 +08:00
|
|
|
self->dnsCache.remove(host, service);
|
2021-12-03 02:22:22 +08:00
|
|
|
promise.sendError(lookup_failed());
|
|
|
|
} else {
|
|
|
|
promise.send(addrs);
|
|
|
|
}
|
|
|
|
});
|
2017-10-16 12:51:11 +08:00
|
|
|
|
2018-11-28 06:41:46 +08:00
|
|
|
wait(ready(result));
|
2018-11-27 12:02:03 +08:00
|
|
|
tcpResolver.cancel();
|
2022-04-04 08:33:18 +08:00
|
|
|
std::vector<NetworkAddress> ret = result.get();
|
|
|
|
self->dnsCache.add(host, service, ret);
|
2018-11-27 11:53:46 +08:00
|
|
|
|
2022-04-04 08:33:18 +08:00
|
|
|
return ret;
|
2020-08-07 04:06:50 +08:00
|
|
|
}
|
|
|
|
|
2022-04-04 08:33:18 +08:00
|
|
|
Future<std::vector<NetworkAddress>> Net2::resolveTCPEndpoint(const std::string& host, const std::string& service) {
|
|
|
|
return resolveTCPEndpoint_impl(this, host, service);
|
2020-08-07 04:06:50 +08:00
|
|
|
}
|
|
|
|
|
2022-04-04 08:33:18 +08:00
|
|
|
Future<std::vector<NetworkAddress>> Net2::resolveTCPEndpointWithDNSCache(const std::string& host,
|
|
|
|
const std::string& service) {
|
|
|
|
Optional<std::vector<NetworkAddress>> cache = dnsCache.find(host, service);
|
|
|
|
if (cache.present()) {
|
|
|
|
return cache.get();
|
|
|
|
}
|
2017-10-16 12:51:11 +08:00
|
|
|
return resolveTCPEndpoint_impl(this, host, service);
|
|
|
|
}
|
|
|
|
|
2022-01-28 06:25:50 +08:00
|
|
|
std::vector<NetworkAddress> Net2::resolveTCPEndpointBlocking(const std::string& host, const std::string& service) {
|
|
|
|
tcp::resolver tcpResolver(reactor.ios);
|
2022-04-02 14:00:39 +08:00
|
|
|
try {
|
|
|
|
auto iter = tcpResolver.resolve(host, service);
|
|
|
|
decltype(iter) end;
|
|
|
|
std::vector<NetworkAddress> addrs;
|
|
|
|
while (iter != end) {
|
|
|
|
auto endpoint = iter->endpoint();
|
|
|
|
auto addr = endpoint.address();
|
|
|
|
if (addr.is_v6()) {
|
|
|
|
addrs.emplace_back(IPAddress(addr.to_v6().to_bytes()), endpoint.port());
|
|
|
|
} else {
|
|
|
|
addrs.emplace_back(addr.to_v4().to_ulong(), endpoint.port());
|
|
|
|
}
|
|
|
|
++iter;
|
2022-01-28 06:25:50 +08:00
|
|
|
}
|
2022-04-04 08:33:18 +08:00
|
|
|
if (addrs.empty()) {
|
|
|
|
throw lookup_failed();
|
|
|
|
}
|
2022-04-02 14:00:39 +08:00
|
|
|
return addrs;
|
|
|
|
} catch (...) {
|
2022-04-04 08:33:18 +08:00
|
|
|
dnsCache.remove(host, service);
|
2022-04-02 14:00:39 +08:00
|
|
|
throw lookup_failed();
|
2022-01-28 06:25:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-04 08:33:18 +08:00
|
|
|
std::vector<NetworkAddress> Net2::resolveTCPEndpointBlockingWithDNSCache(const std::string& host,
|
|
|
|
const std::string& service) {
|
|
|
|
Optional<std::vector<NetworkAddress>> cache = dnsCache.find(host, service);
|
|
|
|
if (cache.present()) {
|
|
|
|
return cache.get();
|
|
|
|
}
|
|
|
|
return resolveTCPEndpointBlocking(host, service);
|
|
|
|
}
|
|
|
|
|
2020-06-21 13:38:40 +08:00
|
|
|
bool Net2::isAddressOnThisHost(NetworkAddress const& addr) const {
|
2021-03-11 02:06:03 +08:00
|
|
|
auto it = addressOnHostCache.find(addr.ip);
|
2017-05-26 04:48:44 +08:00
|
|
|
if (it != addressOnHostCache.end())
|
|
|
|
return it->second;
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
if (addressOnHostCache.size() > 50000)
|
|
|
|
addressOnHostCache.clear(); // Bound cache memory; should not really happen
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
try {
|
|
|
|
boost::asio::io_service ioService;
|
|
|
|
boost::asio::ip::udp::socket socket(ioService);
|
2019-02-27 10:04:03 +08:00
|
|
|
boost::asio::ip::udp::endpoint endpoint(tcpAddress(addr.ip), 1);
|
2017-05-26 04:48:44 +08:00
|
|
|
socket.connect(endpoint);
|
2019-02-27 10:04:03 +08:00
|
|
|
bool local = addr.ip.isV6() ? socket.local_endpoint().address().to_v6().to_bytes() == addr.ip.toV6()
|
|
|
|
: socket.local_endpoint().address().to_v4().to_ulong() == addr.ip.toV4();
|
2017-05-26 04:48:44 +08:00
|
|
|
socket.close();
|
2021-03-11 02:06:03 +08:00
|
|
|
if (local)
|
|
|
|
TraceEvent(SevInfo, "AddressIsOnHost").detail("Address", addr);
|
|
|
|
return addressOnHostCache[addr.ip] = local;
|
|
|
|
} catch (boost::system::system_error e) {
|
|
|
|
TraceEvent(SevWarnAlways, "IsAddressOnHostError")
|
|
|
|
.detail("Address", addr)
|
|
|
|
.detail("ErrDesc", e.what())
|
|
|
|
.detail("ErrCode", e.code().value());
|
|
|
|
return addressOnHostCache[addr.ip] = false;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
Reference<IListener> Net2::listen(NetworkAddress localAddr) {
|
2017-05-26 04:48:44 +08:00
|
|
|
try {
|
2020-02-20 10:37:47 +08:00
|
|
|
#ifndef TLS_DISABLED
|
2021-03-11 02:06:03 +08:00
|
|
|
if (localAddr.isTLS()) {
|
2021-03-05 04:51:24 +08:00
|
|
|
initTLS(ETLSInitState::LISTEN);
|
2021-03-11 02:06:03 +08:00
|
|
|
return Reference<IListener>(new SSLListener(reactor.ios, &this->sslContextVar, localAddr));
|
2020-02-05 06:56:40 +08:00
|
|
|
}
|
2020-02-20 10:37:47 +08:00
|
|
|
#endif
|
2021-03-11 02:06:03 +08:00
|
|
|
return Reference<IListener>(new Listener(reactor.ios, localAddr));
|
2017-05-26 04:48:44 +08:00
|
|
|
} catch (boost::system::system_error const& e) {
|
|
|
|
Error x;
|
2021-03-11 02:06:03 +08:00
|
|
|
if (e.code().value() == EADDRINUSE)
|
2017-05-26 04:48:44 +08:00
|
|
|
x = address_in_use();
|
2021-03-11 02:06:03 +08:00
|
|
|
else if (e.code().value() == EADDRNOTAVAIL)
|
2017-05-26 04:48:44 +08:00
|
|
|
x = invalid_local_address();
|
|
|
|
else
|
|
|
|
x = bind_failed();
|
2018-08-02 05:30:57 +08:00
|
|
|
TraceEvent("Net2ListenError").error(x).detail("Message", e.what());
|
2017-05-26 04:48:44 +08:00
|
|
|
throw x;
|
|
|
|
} catch (std::exception const& e) {
|
|
|
|
Error x = unknown_error();
|
2018-08-02 05:30:57 +08:00
|
|
|
TraceEvent("Net2ListenError").error(x).detail("Message", e.what());
|
2017-05-26 04:48:44 +08:00
|
|
|
throw x;
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (Error& e) {
|
2020-02-27 10:02:56 +08:00
|
|
|
TraceEvent("Net2ListenError").error(e);
|
|
|
|
throw e;
|
2017-05-26 04:48:44 +08:00
|
|
|
} catch (...) {
|
|
|
|
Error x = unknown_error();
|
|
|
|
TraceEvent("Net2ListenError").error(x);
|
|
|
|
throw x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 13:38:40 +08:00
|
|
|
void Net2::getDiskBytes(std::string const& directory, int64_t& free, int64_t& total) {
|
2017-05-26 04:48:44 +08:00
|
|
|
return ::getDiskBytes(directory, free, total);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <sched.h>
|
|
|
|
#endif
|
|
|
|
|
2021-07-25 02:20:51 +08:00
|
|
|
ASIOReactor::ASIOReactor(Net2* net) : do_not_stop(ios), network(net), firstTimer(ios) {
|
2017-05-26 04:48:44 +08:00
|
|
|
#ifdef __linux__
|
|
|
|
// Reactor flags are used only for experimentation, and are platform-specific
|
|
|
|
if (FLOW_KNOBS->REACTOR_FLAGS & 1) {
|
|
|
|
prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
|
|
|
|
printf("Set timerslack to 1ns\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FLOW_KNOBS->REACTOR_FLAGS & 2) {
|
|
|
|
int ret;
|
|
|
|
pthread_t this_thread = pthread_self();
|
|
|
|
struct sched_param params;
|
|
|
|
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
|
|
|
|
ret = pthread_setschedparam(this_thread, SCHED_FIFO, ¶ms);
|
2021-03-11 02:06:03 +08:00
|
|
|
if (ret != 0)
|
|
|
|
printf("Error setting priority (%d %d)\n", ret, errno);
|
2017-05-26 04:48:44 +08:00
|
|
|
else
|
|
|
|
printf("Set scheduler mode to SCHED_FIFO\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-08-29 05:35:48 +08:00
|
|
|
void ASIOReactor::sleep(double sleepTime) {
|
2017-05-26 04:48:44 +08:00
|
|
|
if (sleepTime > FLOW_KNOBS->BUSY_WAIT_THRESHOLD) {
|
|
|
|
if (FLOW_KNOBS->REACTOR_FLAGS & 4) {
|
|
|
|
#ifdef __linux
|
|
|
|
timespec tv;
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_nsec = 20000;
|
2020-08-28 06:31:24 +08:00
|
|
|
nanosleep(&tv, nullptr);
|
2017-05-26 04:48:44 +08:00
|
|
|
#endif
|
2021-03-11 02:06:03 +08:00
|
|
|
} else {
|
2017-05-26 04:48:44 +08:00
|
|
|
sleepTime -= FLOW_KNOBS->BUSY_WAIT_THRESHOLD;
|
|
|
|
if (sleepTime < 4e12) {
|
2021-03-11 02:06:03 +08:00
|
|
|
this->firstTimer.expires_from_now(boost::posix_time::microseconds(int64_t(sleepTime * 1e6)));
|
2017-05-26 04:48:44 +08:00
|
|
|
this->firstTimer.async_wait(&nullWaitHandler);
|
|
|
|
}
|
|
|
|
setProfilingEnabled(0); // The following line generates false positives for slow task profiling
|
|
|
|
ios.run_one();
|
|
|
|
setProfilingEnabled(1);
|
|
|
|
this->firstTimer.cancel();
|
|
|
|
}
|
|
|
|
++network->countASIOEvents;
|
|
|
|
} else if (sleepTime > 0) {
|
|
|
|
if (!(FLOW_KNOBS->REACTOR_FLAGS & 8))
|
|
|
|
threadYield();
|
|
|
|
}
|
2019-08-29 05:35:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASIOReactor::react() {
|
2021-03-11 02:06:03 +08:00
|
|
|
while (ios.poll_one())
|
|
|
|
++network->countASIOEvents; // Make this a task?
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ASIOReactor::wake() {
|
2021-03-11 02:06:03 +08:00
|
|
|
ios.post(nullCompletionHandler);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
2020-12-20 10:09:30 +08:00
|
|
|
} // namespace N2
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-12-27 04:30:00 +08:00
|
|
|
SendBufferIterator::SendBufferIterator(SendBuffer const* p, int limit) : p(p), limit(limit) {
|
|
|
|
ASSERT(limit > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SendBufferIterator::operator++() {
|
|
|
|
limit -= p->bytes_written - p->bytes_sent;
|
|
|
|
if (limit > 0)
|
|
|
|
p = p->next;
|
|
|
|
else
|
|
|
|
p = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::asio::const_buffer SendBufferIterator::operator*() const {
|
|
|
|
return boost::asio::const_buffer(p->data() + p->bytes_sent, std::min(limit, p->bytes_written - p->bytes_sent));
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2020-03-05 12:14:47 +08:00
|
|
|
INetwork* newNet2(const TLSConfig& tlsConfig, bool useThreadPool, bool useMetrics) {
|
2017-05-26 04:48:44 +08:00
|
|
|
try {
|
2021-01-22 06:22:03 +08:00
|
|
|
N2::g_net2 = new N2::Net2(tlsConfig, useThreadPool, useMetrics);
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (boost::system::system_error e) {
|
2017-05-26 04:48:44 +08:00
|
|
|
TraceEvent("Net2InitError").detail("Message", e.what());
|
|
|
|
throw unknown_error();
|
2021-03-11 02:06:03 +08:00
|
|
|
} catch (std::exception const& e) {
|
2017-05-26 04:48:44 +08:00
|
|
|
TraceEvent("Net2InitError").detail("Message", e.what());
|
|
|
|
throw unknown_error();
|
|
|
|
}
|
|
|
|
|
2021-01-22 06:22:03 +08:00
|
|
|
return N2::g_net2;
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct TestGVR {
|
|
|
|
Standalone<StringRef> key;
|
|
|
|
int64_t version;
|
2021-03-11 02:06:03 +08:00
|
|
|
Optional<std::pair<UID, UID>> debugID;
|
|
|
|
Promise<Optional<Standalone<StringRef>>> reply;
|
2017-05-26 04:48:44 +08:00
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
TestGVR() {}
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
template <class Ar>
|
2021-03-11 02:06:03 +08:00
|
|
|
void serialize(Ar& ar) {
|
2018-12-29 02:49:26 +08:00
|
|
|
serializer(ar, key, version, debugID, reply);
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class F>
|
2021-03-11 02:06:03 +08:00
|
|
|
void startThreadF(F&& func) {
|
2017-05-26 04:48:44 +08:00
|
|
|
struct Thing {
|
|
|
|
F f;
|
2021-03-11 02:06:03 +08:00
|
|
|
Thing(F&& f) : f(std::move(f)) {}
|
|
|
|
THREAD_FUNC start(void* p) {
|
|
|
|
Thing* self = (Thing*)p;
|
|
|
|
self->f();
|
|
|
|
delete self;
|
|
|
|
THREAD_RETURN;
|
|
|
|
}
|
2017-05-26 04:48:44 +08:00
|
|
|
};
|
|
|
|
Thing* t = new Thing(std::move(func));
|
|
|
|
startThread(Thing::start, t);
|
|
|
|
}
|
|
|
|
|
2021-03-11 02:06:03 +08:00
|
|
|
void net2_test(){
|
2017-05-26 04:48:44 +08:00
|
|
|
/*printf("ThreadSafeQueue test\n");
|
|
|
|
printf(" Interface: ");
|
|
|
|
ThreadSafeQueue<int> tq;
|
|
|
|
ASSERT( tq.canSleep() == true );
|
|
|
|
|
|
|
|
ASSERT( tq.push( 1 ) == true ) ;
|
|
|
|
ASSERT( tq.push( 2 ) == false );
|
|
|
|
ASSERT( tq.push( 3 ) == false );
|
|
|
|
|
|
|
|
ASSERT( tq.pop().get() == 1 );
|
|
|
|
ASSERT( tq.pop().get() == 2 );
|
|
|
|
ASSERT( tq.push( 4 ) == false );
|
|
|
|
ASSERT( tq.pop().get() == 3 );
|
|
|
|
ASSERT( tq.pop().get() == 4 );
|
|
|
|
ASSERT( !tq.pop().present() );
|
|
|
|
printf("OK\n");
|
|
|
|
|
|
|
|
printf("Threaded: ");
|
|
|
|
Event finished, finished2;
|
|
|
|
int thread1Iterations = 1000000, thread2Iterations = 100000;
|
|
|
|
|
|
|
|
if (thread1Iterations)
|
2021-03-11 02:06:03 +08:00
|
|
|
startThreadF([&](){
|
|
|
|
printf("Thread1\n");
|
|
|
|
for(int i=0; i<thread1Iterations; i++)
|
|
|
|
tq.push(i);
|
|
|
|
printf("T1Done\n");
|
|
|
|
finished.set();
|
|
|
|
});
|
2017-05-26 04:48:44 +08:00
|
|
|
if (thread2Iterations)
|
2021-03-11 02:06:03 +08:00
|
|
|
startThreadF([&](){
|
|
|
|
printf("Thread2\n");
|
|
|
|
for(int i=0; i<thread2Iterations; i++)
|
|
|
|
tq.push(i + (1<<20));
|
|
|
|
printf("T2Done\n");
|
|
|
|
finished2.set();
|
|
|
|
});
|
2017-05-26 04:48:44 +08:00
|
|
|
int c = 0, mx[2]={0, 1<<20}, p = 0;
|
|
|
|
while (c < thread1Iterations + thread2Iterations)
|
|
|
|
{
|
2021-03-11 02:06:03 +08:00
|
|
|
Optional<int> i = tq.pop();
|
|
|
|
if (i.present()) {
|
|
|
|
int v = i.get();
|
|
|
|
++c;
|
|
|
|
if (mx[v>>20] != v)
|
|
|
|
printf("Wrong value dequeued!\n");
|
|
|
|
ASSERT( mx[v>>20] == v );
|
|
|
|
mx[v>>20] = v + 1;
|
|
|
|
} else {
|
|
|
|
++p;
|
|
|
|
_mm_pause();
|
|
|
|
}
|
|
|
|
if ((c&3)==0) tq.canSleep();
|
|
|
|
}
|
|
|
|
printf("%d %d %x %x %s\n", c, p, mx[0], mx[1], mx[0]==thread1Iterations && mx[1]==(1<<20)+thread2Iterations ? "OK" :
|
|
|
|
"FAIL");
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
finished.block();
|
|
|
|
finished2.block();
|
|
|
|
|
|
|
|
|
2018-10-30 06:26:28 +08:00
|
|
|
g_network = newNet2(); // for promise serialization below
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
Endpoint destination;
|
|
|
|
|
2019-01-09 06:36:01 +08:00
|
|
|
printf(" Used: %lld\n", FastAllocator<4096>::getTotalMemory());
|
2017-05-26 04:48:44 +08:00
|
|
|
|
|
|
|
char junk[100];
|
|
|
|
|
|
|
|
double before = timer();
|
|
|
|
|
2021-09-17 08:42:34 +08:00
|
|
|
std::vector<TestGVR> reqs;
|
2017-05-26 04:48:44 +08:00
|
|
|
reqs.reserve( 10000 );
|
|
|
|
|
|
|
|
int totalBytes = 0;
|
|
|
|
for(int j=0; j<1000; j++) {
|
2021-03-11 02:06:03 +08:00
|
|
|
UnsentPacketQueue unsent;
|
|
|
|
ReliablePacketList reliable;
|
|
|
|
|
|
|
|
reqs.resize(10000);
|
|
|
|
for(int i=0; i<10000; i++) {
|
|
|
|
TestGVR &req = reqs[i];
|
|
|
|
req.key = LiteralStringRef("Foobar");
|
|
|
|
|
|
|
|
SerializeSource<TestGVR> what(req);
|
|
|
|
|
|
|
|
SendBuffer* pb = unsent.getWriteBuffer();
|
|
|
|
ReliablePacket* rp = new ReliablePacket; // 0
|
|
|
|
|
|
|
|
PacketWriter wr(pb,rp,AssumeVersion(g_network->protocolVersion()));
|
|
|
|
//BinaryWriter wr;
|
|
|
|
SplitBuffer packetLen;
|
|
|
|
uint32_t len = 0;
|
|
|
|
wr.writeAhead(sizeof(len), &packetLen);
|
|
|
|
wr << destination.token;
|
|
|
|
//req.reply.getEndpoint();
|
|
|
|
what.serializePacketWriter(wr);
|
|
|
|
//wr.serializeBytes(junk, 43);
|
|
|
|
|
|
|
|
unsent.setWriteBuffer(wr.finish());
|
|
|
|
len = wr.size() - sizeof(len);
|
|
|
|
packetLen.write(&len, sizeof(len));
|
|
|
|
|
|
|
|
//totalBytes += wr.getLength();
|
|
|
|
totalBytes += wr.size();
|
|
|
|
|
|
|
|
if (rp) reliable.insert(rp);
|
|
|
|
}
|
|
|
|
reqs.clear();
|
|
|
|
unsent.discardAll();
|
|
|
|
reliable.discardAll();
|
2017-05-26 04:48:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
printf("SimSend x 1Kx10K: %0.2f sec\n", timer()-before);
|
|
|
|
printf(" Bytes: %d\n", totalBytes);
|
2019-01-09 06:36:01 +08:00
|
|
|
printf(" Used: %lld\n", FastAllocator<4096>::getTotalMemory());
|
2017-05-26 04:48:44 +08:00
|
|
|
*/
|
|
|
|
};
|