mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
add tracing for nfs
Summary: This diff adds tracking for nfs, based on the implementation of that of `FuseChannel`. Also commented below few questions on the implementation before working on integrating to `strace`. Reviewed By: chadaustin Differential Revision: D29279126 fbshipit-source-id: de6bb36dfbe2f550a91f2bf254616bbc639c0c3d
This commit is contained in:
parent
dd04dc0d95
commit
d54083bd53
@ -18,6 +18,7 @@
|
|||||||
#include <folly/futures/Future.h>
|
#include <folly/futures/Future.h>
|
||||||
#include "eden/fs/nfs/NfsdRpc.h"
|
#include "eden/fs/nfs/NfsdRpc.h"
|
||||||
#include "eden/fs/utils/Clock.h"
|
#include "eden/fs/utils/Clock.h"
|
||||||
|
#include "eden/fs/utils/IDGen.h"
|
||||||
#include "eden/fs/utils/SystemError.h"
|
#include "eden/fs/utils/SystemError.h"
|
||||||
|
|
||||||
namespace folly {
|
namespace folly {
|
||||||
@ -27,6 +28,10 @@ class Executor;
|
|||||||
namespace facebook::eden {
|
namespace facebook::eden {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
constexpr size_t kTraceBusCapacity = 25000;
|
||||||
|
static_assert(sizeof(NfsTraceEvent) == 40);
|
||||||
|
static_assert(kTraceBusCapacity * sizeof(NfsTraceEvent) == 1000000);
|
||||||
|
|
||||||
class Nfsd3ServerProcessor final : public RpcServerProcessor {
|
class Nfsd3ServerProcessor final : public RpcServerProcessor {
|
||||||
public:
|
public:
|
||||||
explicit Nfsd3ServerProcessor(
|
explicit Nfsd3ServerProcessor(
|
||||||
@ -34,12 +39,16 @@ class Nfsd3ServerProcessor final : public RpcServerProcessor {
|
|||||||
const folly::Logger* straceLogger,
|
const folly::Logger* straceLogger,
|
||||||
CaseSensitivity caseSensitive,
|
CaseSensitivity caseSensitive,
|
||||||
uint32_t iosize,
|
uint32_t iosize,
|
||||||
folly::Promise<Nfsd3::StopData>& stopPromise)
|
folly::Promise<Nfsd3::StopData>& stopPromise,
|
||||||
|
std::atomic<size_t>& traceDetailedArguments,
|
||||||
|
std::shared_ptr<TraceBus<NfsTraceEvent>>& traceBus)
|
||||||
: dispatcher_(std::move(dispatcher)),
|
: dispatcher_(std::move(dispatcher)),
|
||||||
straceLogger_(straceLogger),
|
straceLogger_(straceLogger),
|
||||||
caseSensitive_(caseSensitive),
|
caseSensitive_(caseSensitive),
|
||||||
iosize_(iosize),
|
iosize_(iosize),
|
||||||
stopPromise_{stopPromise} {}
|
stopPromise_{stopPromise},
|
||||||
|
traceDetailedArguments_(traceDetailedArguments),
|
||||||
|
traceBus_(traceBus) {}
|
||||||
|
|
||||||
Nfsd3ServerProcessor(const Nfsd3ServerProcessor&) = delete;
|
Nfsd3ServerProcessor(const Nfsd3ServerProcessor&) = delete;
|
||||||
Nfsd3ServerProcessor(Nfsd3ServerProcessor&&) = delete;
|
Nfsd3ServerProcessor(Nfsd3ServerProcessor&&) = delete;
|
||||||
@ -113,6 +122,8 @@ class Nfsd3ServerProcessor final : public RpcServerProcessor {
|
|||||||
// lifetime of nfs3d. The way we currently enforce this is by waiting for
|
// lifetime of nfs3d. The way we currently enforce this is by waiting for
|
||||||
// this promise to be set before destroying of the nfs3d.
|
// this promise to be set before destroying of the nfs3d.
|
||||||
folly::Promise<Nfsd3::StopData>& stopPromise_;
|
folly::Promise<Nfsd3::StopData>& stopPromise_;
|
||||||
|
std::atomic<size_t>& traceDetailedArguments_;
|
||||||
|
std::shared_ptr<TraceBus<NfsTraceEvent>>& traceBus_;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1742,7 +1753,16 @@ ImmediateFuture<folly::Unit> Nfsd3ServerProcessor::dispatchRpc(
|
|||||||
"{}({})",
|
"{}({})",
|
||||||
handlerEntry.name,
|
handlerEntry.name,
|
||||||
handlerEntry.formatArgs(deser));
|
handlerEntry.formatArgs(deser));
|
||||||
return (this->*handlerEntry.handler)(std::move(deser), std::move(ser), xid);
|
if (traceDetailedArguments_.load(std::memory_order_acquire)) {
|
||||||
|
traceBus_->publish(
|
||||||
|
NfsTraceEvent::start(xid, procNumber, handlerEntry.formatArgs(deser)));
|
||||||
|
} else {
|
||||||
|
traceBus_->publish(NfsTraceEvent::start(xid, procNumber));
|
||||||
|
}
|
||||||
|
return (this->*handlerEntry.handler)(std::move(deser), std::move(ser), xid)
|
||||||
|
.ensure([this, xid, procNumber]() {
|
||||||
|
traceBus_->publish(NfsTraceEvent::finish(xid, procNumber));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Nfsd3ServerProcessor::onSocketClosed() {
|
void Nfsd3ServerProcessor::onSocketClosed() {
|
||||||
@ -1769,12 +1789,36 @@ Nfsd3::Nfsd3(
|
|||||||
straceLogger,
|
straceLogger,
|
||||||
caseSensitive,
|
caseSensitive,
|
||||||
iosize,
|
iosize,
|
||||||
stopPromise_),
|
stopPromise_,
|
||||||
|
traceDetailedArguments_,
|
||||||
|
traceBus_),
|
||||||
evb,
|
evb,
|
||||||
std::move(threadPool)),
|
std::move(threadPool)),
|
||||||
processAccessLog_(std::move(processNameCache)),
|
processAccessLog_(std::move(processNameCache)),
|
||||||
invalidationExecutor_{
|
invalidationExecutor_{
|
||||||
folly::SerialExecutor::create(folly::getGlobalCPUExecutor())} {}
|
folly::SerialExecutor::create(folly::getGlobalCPUExecutor())},
|
||||||
|
traceDetailedArguments_{0},
|
||||||
|
traceBus_{
|
||||||
|
TraceBus<NfsTraceEvent>::create("NfsTrace", kTraceBusCapacity)} {
|
||||||
|
traceSubscriptionHandles_.push_back(traceBus_->subscribeFunction(
|
||||||
|
"NFS request tracking", [this](const NfsTraceEvent& event) {
|
||||||
|
switch (event.getType()) {
|
||||||
|
case NfsTraceEvent::START: {
|
||||||
|
auto state = telemetryState_.wlock();
|
||||||
|
// allow duplicated calls since the client may retry a request
|
||||||
|
(void)state->requests.emplace(
|
||||||
|
event.getXid(), OutstandingRequest{event.getXid()});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case NfsTraceEvent::FINISH: {
|
||||||
|
auto state = telemetryState_.wlock();
|
||||||
|
// allow duplicated calls since the client may retry a request
|
||||||
|
(void)state->requests.erase(event.getXid());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
void Nfsd3::initialize(folly::SocketAddress addr, bool registerWithRpcbind) {
|
void Nfsd3::initialize(folly::SocketAddress addr, bool registerWithRpcbind) {
|
||||||
server_.initialize(addr);
|
server_.initialize(addr);
|
||||||
@ -1812,6 +1856,24 @@ folly::Future<folly::Unit> Nfsd3::flushInvalidations() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Nfsd3::OutstandingRequest> Nfsd3::getOutstandingRequests() {
|
||||||
|
std::vector<Nfsd3::OutstandingRequest> outstandingCalls;
|
||||||
|
|
||||||
|
for (const auto& entry : telemetryState_.rlock()->requests) {
|
||||||
|
outstandingCalls.push_back(entry.second);
|
||||||
|
}
|
||||||
|
return outstandingCalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
TraceDetailedArgumentsHandle Nfsd3::traceDetailedArguments() {
|
||||||
|
auto handle =
|
||||||
|
std::shared_ptr<void>(nullptr, [© = traceDetailedArguments_](void*) {
|
||||||
|
copy.fetch_sub(1, std::memory_order_acq_rel);
|
||||||
|
});
|
||||||
|
traceDetailedArguments_.fetch_add(1, std::memory_order_acq_rel);
|
||||||
|
return handle;
|
||||||
|
};
|
||||||
|
|
||||||
Nfsd3::~Nfsd3() {
|
Nfsd3::~Nfsd3() {
|
||||||
// TODO(xavierd): wait for the pending requests,
|
// TODO(xavierd): wait for the pending requests,
|
||||||
// Note the socket will already have been torn down, as this is only destroyed
|
// Note the socket will already have been torn down, as this is only destroyed
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "eden/fs/nfs/NfsDispatcher.h"
|
#include "eden/fs/nfs/NfsDispatcher.h"
|
||||||
#include "eden/fs/nfs/rpc/Server.h"
|
#include "eden/fs/nfs/rpc/Server.h"
|
||||||
|
#include "eden/fs/telemetry/TraceBus.h"
|
||||||
#include "eden/fs/utils/CaseSensitivity.h"
|
#include "eden/fs/utils/CaseSensitivity.h"
|
||||||
#include "eden/fs/utils/ProcessAccessLog.h"
|
#include "eden/fs/utils/ProcessAccessLog.h"
|
||||||
|
|
||||||
@ -26,6 +27,61 @@ namespace facebook::eden {
|
|||||||
class Notifications;
|
class Notifications;
|
||||||
class ProcessNameCache;
|
class ProcessNameCache;
|
||||||
|
|
||||||
|
using TraceDetailedArgumentsHandle = std::shared_ptr<void>;
|
||||||
|
|
||||||
|
struct NfsTraceEvent : TraceEventBase {
|
||||||
|
enum Type : unsigned char {
|
||||||
|
START,
|
||||||
|
FINISH,
|
||||||
|
};
|
||||||
|
|
||||||
|
NfsTraceEvent() = delete;
|
||||||
|
|
||||||
|
static NfsTraceEvent start(uint32_t xid, uint32_t procNumber) {
|
||||||
|
return NfsTraceEvent{
|
||||||
|
xid, procNumber, StartDetails{std::unique_ptr<std::string>{}}};
|
||||||
|
}
|
||||||
|
|
||||||
|
static NfsTraceEvent
|
||||||
|
start(uint32_t xid, uint32_t procNumber, std::string&& args) {
|
||||||
|
return NfsTraceEvent{
|
||||||
|
xid, procNumber, StartDetails{std::make_unique<std::string>(args)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
static NfsTraceEvent finish(uint32_t xid, uint32_t procNumber) {
|
||||||
|
return NfsTraceEvent{xid, procNumber, FinishDetails{}};
|
||||||
|
}
|
||||||
|
|
||||||
|
Type getType() const {
|
||||||
|
return std::holds_alternative<StartDetails>(details_) ? Type::START
|
||||||
|
: Type::FINISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getXid() const {
|
||||||
|
return xid_;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t getProcNumber() const {
|
||||||
|
return procNumber_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct StartDetails {
|
||||||
|
std::unique_ptr<std::string> arguments;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FinishDetails {};
|
||||||
|
|
||||||
|
using Details = std::variant<StartDetails, FinishDetails>;
|
||||||
|
|
||||||
|
NfsTraceEvent(uint32_t xid, uint32_t procNumber, Details&& details)
|
||||||
|
: xid_{xid}, procNumber_{procNumber}, details_{std::move(details)} {}
|
||||||
|
|
||||||
|
uint32_t xid_;
|
||||||
|
uint32_t procNumber_;
|
||||||
|
Details details_;
|
||||||
|
};
|
||||||
|
|
||||||
class Nfsd3 {
|
class Nfsd3 {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@ -97,6 +153,10 @@ class Nfsd3 {
|
|||||||
|
|
||||||
struct StopData {};
|
struct StopData {};
|
||||||
|
|
||||||
|
struct OutstandingRequest {
|
||||||
|
uint32_t xid;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a future that will be triggered on unmount.
|
* Return a future that will be triggered on unmount.
|
||||||
*/
|
*/
|
||||||
@ -111,11 +171,38 @@ class Nfsd3 {
|
|||||||
Nfsd3& operator=(const Nfsd3&) = delete;
|
Nfsd3& operator=(const Nfsd3&) = delete;
|
||||||
Nfsd3& operator=(Nfsd3&&) = delete;
|
Nfsd3& operator=(Nfsd3&&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the approximate set of outstanding NFS requests. Since
|
||||||
|
* telemetry is tracked on a background thread, the result may very slightly
|
||||||
|
* lag reality.
|
||||||
|
*/
|
||||||
|
std::vector<Nfsd3::OutstandingRequest> getOutstandingRequests();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* While the returned handle is alive, NfsTraceEvents published on the
|
||||||
|
* TraceBus will have detailed argument strings.
|
||||||
|
*/
|
||||||
|
TraceDetailedArgumentsHandle traceDetailedArguments();
|
||||||
|
|
||||||
|
TraceBus<NfsTraceEvent>& getTraceBus() {
|
||||||
|
return *traceBus_;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct TelemetryState {
|
||||||
|
std::unordered_map<uint64_t, OutstandingRequest> requests;
|
||||||
|
};
|
||||||
|
folly::Synchronized<TelemetryState> telemetryState_;
|
||||||
|
std::vector<TraceSubscriptionHandle<NfsTraceEvent>> traceSubscriptionHandles_;
|
||||||
|
|
||||||
folly::Promise<StopData> stopPromise_;
|
folly::Promise<StopData> stopPromise_;
|
||||||
RpcServer server_;
|
RpcServer server_;
|
||||||
ProcessAccessLog processAccessLog_;
|
ProcessAccessLog processAccessLog_;
|
||||||
folly::Executor::KeepAlive<folly::Executor> invalidationExecutor_;
|
folly::Executor::KeepAlive<folly::Executor> invalidationExecutor_;
|
||||||
|
std::atomic<size_t> traceDetailedArguments_;
|
||||||
|
// The TraceBus must be the last member because its subscribed functions may
|
||||||
|
// close over `this` and can run until the TraceBus itself is deallocated.
|
||||||
|
std::shared_ptr<TraceBus<NfsTraceEvent>> traceBus_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace facebook::eden
|
} // namespace facebook::eden
|
||||||
|
Loading…
Reference in New Issue
Block a user