2016-05-12 23:43:17 +03:00
|
|
|
/*
|
2017-01-21 09:02:33 +03:00
|
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
2016-05-12 23:43:17 +03:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
*/
|
2018-03-16 22:08:02 +03:00
|
|
|
#include "eden/fs/fuse/RequestData.h"
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2017-06-22 23:39:57 +03:00
|
|
|
#include <folly/experimental/logging/xlog.h>
|
2016-06-10 21:26:35 +03:00
|
|
|
|
2018-03-16 22:08:02 +03:00
|
|
|
#include "eden/fs/fuse/Dispatcher.h"
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
using namespace folly;
|
2016-06-10 21:26:35 +03:00
|
|
|
using namespace std::chrono;
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
|
2018-03-20 03:01:15 +03:00
|
|
|
const std::string RequestData::kKey("fuse");
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
RequestData::RequestData(
|
|
|
|
FuseChannel* channel,
|
|
|
|
const fuse_in_header& fuseHeader,
|
|
|
|
Dispatcher* dispatcher)
|
2018-01-26 22:17:36 +03:00
|
|
|
: channel_(channel), fuseHeader_(fuseHeader), dispatcher_(dispatcher) {}
|
2017-09-09 05:15:25 +03:00
|
|
|
|
|
|
|
RequestData::~RequestData() {
|
2018-01-03 03:25:07 +03:00
|
|
|
channel_->finishRequest(fuseHeader_);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:07 +03:00
|
|
|
void RequestData::interrupt() {
|
|
|
|
// I don't believe that we have to deal with racing to
|
|
|
|
// process multiple concurrent interrupt() calls.
|
|
|
|
// The potential race is between an interrupt() call
|
|
|
|
// and the completion of the request.
|
|
|
|
if (!interrupted_) {
|
|
|
|
interrupter_.cancel();
|
|
|
|
interrupted_ = true;
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-24 20:37:48 +03:00
|
|
|
bool RequestData::isFuseRequest() {
|
|
|
|
return folly::RequestContext::get()->getContextData(kKey) != nullptr;
|
|
|
|
}
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
RequestData& RequestData::get() {
|
2018-01-18 00:29:59 +03:00
|
|
|
const auto data = folly::RequestContext::get()->getContextData(kKey);
|
2016-05-12 23:43:17 +03:00
|
|
|
if (UNLIKELY(!data)) {
|
2017-06-22 23:39:57 +03:00
|
|
|
XLOG(FATAL) << "boom for missing RequestData";
|
2016-05-12 23:43:17 +03:00
|
|
|
throw std::runtime_error("no fuse request data set in this context!");
|
|
|
|
}
|
|
|
|
return *dynamic_cast<RequestData*>(data);
|
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
RequestData& RequestData::create(
|
|
|
|
FuseChannel* channel,
|
|
|
|
const fuse_in_header& fuseHeader,
|
|
|
|
Dispatcher* dispatcher) {
|
2016-05-12 23:43:17 +03:00
|
|
|
folly::RequestContext::get()->setContextData(
|
2018-01-03 03:25:03 +03:00
|
|
|
RequestData::kKey,
|
|
|
|
std::make_unique<RequestData>(channel, fuseHeader, dispatcher));
|
2016-05-12 23:43:17 +03:00
|
|
|
return get();
|
|
|
|
}
|
|
|
|
|
2017-03-31 21:23:02 +03:00
|
|
|
Future<folly::Unit> RequestData::startRequest(
|
2017-08-18 21:43:55 +03:00
|
|
|
ThreadLocalEdenStats* stats,
|
2017-03-31 21:23:02 +03:00
|
|
|
EdenStats::HistogramPtr histogram) {
|
2016-06-10 21:26:35 +03:00
|
|
|
startTime_ = steady_clock::now();
|
|
|
|
DCHECK(latencyHistogram_ == nullptr);
|
2017-03-31 21:23:02 +03:00
|
|
|
latencyHistogram_ = histogram;
|
|
|
|
stats_ = stats;
|
2016-06-10 21:26:35 +03:00
|
|
|
return folly::Unit{};
|
|
|
|
}
|
|
|
|
|
|
|
|
void RequestData::finishRequest() {
|
2018-01-18 00:29:59 +03:00
|
|
|
const auto now = steady_clock::now();
|
|
|
|
const auto now_since_epoch = duration_cast<seconds>(now.time_since_epoch());
|
|
|
|
const auto diff = duration_cast<microseconds>(now - startTime_);
|
2017-10-20 21:32:32 +03:00
|
|
|
stats_->get()->recordLatency(latencyHistogram_, diff, now_since_epoch);
|
2016-06-10 21:26:35 +03:00
|
|
|
latencyHistogram_ = nullptr;
|
2017-03-31 21:23:02 +03:00
|
|
|
stats_ = nullptr;
|
2016-06-10 21:26:35 +03:00
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
fuse_in_header RequestData::stealReq() {
|
|
|
|
if (fuseHeader_.opcode == 0) {
|
2016-05-12 23:43:17 +03:00
|
|
|
throw std::runtime_error("req_ has been released");
|
|
|
|
}
|
2018-01-03 03:25:03 +03:00
|
|
|
fuse_in_header res = fuseHeader_;
|
|
|
|
fuseHeader_.opcode = 0;
|
2016-05-12 23:43:17 +03:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-01-03 03:25:03 +03:00
|
|
|
const fuse_in_header& RequestData::getReq() const {
|
|
|
|
if (fuseHeader_.opcode == 0) {
|
2016-05-12 23:43:17 +03:00
|
|
|
throw std::runtime_error("req_ has been released");
|
|
|
|
}
|
2018-01-03 03:25:03 +03:00
|
|
|
return fuseHeader_;
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
2018-03-20 20:18:29 +03:00
|
|
|
const fuse_in_header& RequestData::examineReq() const {
|
|
|
|
// Will just return the fuseHeader_ and not throw(unlike getReq)
|
|
|
|
// The caller is responsible to check the opcode and ignore if zero
|
|
|
|
return fuseHeader_;
|
|
|
|
}
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
Dispatcher* RequestData::getDispatcher() const {
|
2017-09-09 05:15:25 +03:00
|
|
|
return dispatcher_;
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RequestData::wasInterrupted() const {
|
2018-01-03 03:25:07 +03:00
|
|
|
return interrupted_;
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void RequestData::replyError(int err) {
|
2018-01-03 03:25:03 +03:00
|
|
|
channel_->replyError(stealReq(), err);
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void RequestData::replyNone() {
|
2018-01-03 03:25:03 +03:00
|
|
|
stealReq();
|
2016-05-12 23:43:17 +03:00
|
|
|
}
|
2017-06-22 23:39:57 +03:00
|
|
|
|
|
|
|
void RequestData::systemErrorHandler(const std::system_error& err) {
|
|
|
|
int errnum = EIO;
|
|
|
|
if (err.code().category() == std::system_category()) {
|
|
|
|
errnum = err.code().value();
|
|
|
|
}
|
|
|
|
XLOG(DBG5) << folly::exceptionStr(err);
|
|
|
|
RequestData::get().replyError(errnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RequestData::genericErrorHandler(const std::exception& err) {
|
|
|
|
XLOG(DBG5) << folly::exceptionStr(err);
|
|
|
|
RequestData::get().replyError(EIO);
|
|
|
|
}
|
2018-03-20 03:01:15 +03:00
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace eden
|
|
|
|
} // namespace facebook
|