mirror of
https://github.com/facebook/sapling.git
synced 2024-10-08 07:49:11 +03:00
1fac9783e3
Summary: This is really a continuation of D13479516; the issue is that the osxfuse kernel module is very eager to recycle `unique` request id values, recycling them before our code has had a chance to update internal state. This diff re-keys the requests map so that we generate our own sequence of identifiers to use as the key rather than the fuse protocol `unique` value. Because we cannot reliably track by `unique` value we also cannot reliably implement interrupt support. We've never really tested interrupt support, and it relies on functionality in folly futures that hasn't really been tested or proven either, so I've removed that functionality as part of this diff. That allows simplifying some code in RequestData and FuseChannel; we're now able to simply tack an `.ensure` on the end of the future chain to ensure that we remove the entry from the map once the future is resolved, successfully or otherwise. Reviewed By: chadaustin Differential Revision: D13679964 fbshipit-source-id: c1081a868c4061de2a725589ec1614959a8e9316
116 lines
3.3 KiB
C++
116 lines
3.3 KiB
C++
/*
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
#pragma once
|
|
#include <folly/futures/Future.h>
|
|
#include <folly/io/async/Request.h>
|
|
#include <atomic>
|
|
#include <utility>
|
|
#include "eden/fs/fuse/EdenStats.h"
|
|
#include "eden/fs/fuse/FuseChannel.h"
|
|
#include "eden/fs/fuse/FuseTypes.h"
|
|
|
|
namespace facebook {
|
|
namespace eden {
|
|
|
|
class Dispatcher;
|
|
|
|
class RequestData : public folly::RequestData {
|
|
FuseChannel* channel_;
|
|
fuse_in_header fuseHeader_;
|
|
// Needed to track stats
|
|
std::chrono::time_point<std::chrono::steady_clock> startTime_;
|
|
EdenStats::HistogramPtr latencyHistogram_{nullptr};
|
|
ThreadLocalEdenStats* stats_{nullptr};
|
|
Dispatcher* dispatcher_{nullptr};
|
|
|
|
fuse_in_header stealReq();
|
|
|
|
public:
|
|
static const std::string kKey;
|
|
RequestData(const RequestData&) = delete;
|
|
RequestData& operator=(const RequestData&) = delete;
|
|
RequestData(RequestData&&) = default;
|
|
RequestData& operator=(RequestData&&) = default;
|
|
explicit RequestData(
|
|
FuseChannel* channel,
|
|
const fuse_in_header& fuseHeader,
|
|
Dispatcher* dispatcher);
|
|
static RequestData& get();
|
|
static RequestData& create(
|
|
FuseChannel* channel,
|
|
const fuse_in_header& fuseHeader,
|
|
Dispatcher* dispatcher);
|
|
|
|
bool hasCallback() override {
|
|
return false;
|
|
}
|
|
|
|
// Returns true if the current context is being called from inside
|
|
// a FUSE request, false otherwise.
|
|
static bool isFuseRequest();
|
|
|
|
void startRequest(
|
|
ThreadLocalEdenStats* stats,
|
|
EdenStats::HistogramPtr histogram);
|
|
void finishRequest();
|
|
|
|
// Returns the associated dispatcher instance
|
|
Dispatcher* getDispatcher() const;
|
|
|
|
// Returns the underlying fuse request, throwing an error if it has
|
|
// already been released
|
|
const fuse_in_header& getReq() const;
|
|
|
|
// Returns the underlying fuse request. Unlike getReq this function doesn't
|
|
// throw. The caller is responsible to verify that the fuse_in_header is valid
|
|
// by checking if (fuseHeader.opcode != 0)
|
|
const fuse_in_header& examineReq() const;
|
|
|
|
/** Append error handling clauses to a future chain
|
|
* These clauses result in reporting a fuse request error back to the
|
|
* kernel. */
|
|
template <typename T>
|
|
folly::Future<folly::Unit> catchErrors(folly::Future<T>&& fut) {
|
|
return std::move(fut)
|
|
.onError(systemErrorHandler)
|
|
.onError(genericErrorHandler)
|
|
.ensure([] { RequestData::get().finishRequest(); });
|
|
}
|
|
|
|
static void systemErrorHandler(const std::system_error& err);
|
|
static void genericErrorHandler(const std::exception& err);
|
|
|
|
template <typename T>
|
|
void sendReply(const T& payload) {
|
|
channel_->sendReply(stealReq(), payload);
|
|
}
|
|
|
|
void sendReply(folly::ByteRange bytes) {
|
|
channel_->sendReply(stealReq(), bytes);
|
|
}
|
|
|
|
void sendReply(folly::fbvector<iovec>&& vec) {
|
|
channel_->sendReply(stealReq(), std::move(vec));
|
|
}
|
|
|
|
void sendReply(folly::StringPiece piece) {
|
|
channel_->sendReply(stealReq(), folly::ByteRange(piece));
|
|
}
|
|
|
|
// Reply with a negative errno value or 0 for success
|
|
void replyError(int err);
|
|
|
|
// Don't send a reply, just release req_
|
|
void replyNone();
|
|
};
|
|
|
|
} // namespace eden
|
|
} // namespace facebook
|