sapling/eden/fs/takeover/TakeoverClient.cpp
Xavier Deguillard 695c24f493 fs: ifdef linux/macos only files
Summary:
These don't compile on Windows, and in order to get mode/win to compile, we
need to avoid compiling their contents. Ideally, we could do that in the
TARGETS files with the select statement, but that's not available in fbcode.
Thus, we do the next best thing: ifdef the file entirely.

Reviewed By: wez

Differential Revision: D23871728

fbshipit-source-id: b4d9df6503eaa008e649afd7bdc665cd37a9585d
2020-09-23 12:20:41 -07:00

124 lines
4.2 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#ifndef _WIN32
#include "eden/fs/takeover/TakeoverClient.h"
#include <folly/io/Cursor.h>
#include <folly/io/async/EventBase.h>
#include <folly/logging/xlog.h>
#include <thrift/lib/cpp2/protocol/Serializer.h>
#include "eden/fs/takeover/TakeoverData.h"
#include "eden/fs/takeover/gen-cpp2/takeover_types.h"
#include "eden/fs/utils/FutureUnixSocket.h"
using apache::thrift::CompactSerializer;
using std::string;
/**
* Five minutes is a high default value. This could be lowered back to one
* minute after takeover no longer does O(loaded) expensive save operations.
*/
DEFINE_int32(
takeoverReceiveTimeout,
300,
"Timeout for receiving takeover data from old process in seconds");
namespace facebook {
namespace eden {
TakeoverData takeoverMounts(
AbsolutePathPiece socketPath,
bool shouldPing,
const std::set<int32_t>& supportedVersions) {
folly::EventBase evb;
folly::Expected<UnixSocket::Message, folly::exception_wrapper>
expectedMessage;
auto connectTimeout = std::chrono::seconds(1);
FutureUnixSocket socket;
socket.connect(&evb, socketPath.stringPiece(), connectTimeout)
.thenValue([&socket, supportedVersions](auto&&) {
// Send our protocol version so that the server knows
// whether we're capable of handshaking successfully
TakeoverVersionQuery query;
*query.versions_ref() = supportedVersions;
return socket.send(
CompactSerializer::serialize<folly::IOBufQueue>(query).move());
})
.thenValue([&socket](auto&&) {
// Wait for a response. this will either be a "ready" ping or the
// takeover data depending on the server protocol
auto timeout = std::chrono::seconds(FLAGS_takeoverReceiveTimeout);
return socket.receive(timeout);
})
.thenValue([&socket, shouldPing](UnixSocket::Message&& msg) {
if (TakeoverData::isPing(&msg.data)) {
if (shouldPing) {
// Just send an empty message back here, the server knows it sent a
// ping so it does not need to parse the message.
UnixSocket::Message ping;
return socket.send(std::move(ping)).thenValue([&socket](auto&&) {
// Wait for the takeover data response
auto timeout = std::chrono::seconds(FLAGS_takeoverReceiveTimeout);
return socket.receive(timeout);
});
} else {
// This should only be hit during integration tests.
return folly::makeFuture<UnixSocket::Message>(
folly::exception_wrapper(std::runtime_error(
"ping received but should not respond")));
}
} else {
// Older versions of EdenFS will not send a "ready" ping and
// could simply send the takeover data.
return folly::makeFuture<UnixSocket::Message>(std::move(msg));
}
})
.thenValue([&expectedMessage](UnixSocket::Message&& msg) {
expectedMessage = std::move(msg);
})
.thenError([&expectedMessage](folly::exception_wrapper&& ew) {
expectedMessage = folly::makeUnexpected(std::move(ew));
})
.ensure([&evb] { evb.terminateLoopSoon(); });
evb.loop();
if (!expectedMessage) {
XLOG(ERR) << "error receiving takeover data: " << expectedMessage.error();
expectedMessage.error().throw_exception();
}
auto& message = expectedMessage.value();
auto data = TakeoverData::deserialize(&message.data);
// Add 2 here for the lock file and the thrift socket
if (data.mountPoints.size() + 2 != message.files.size()) {
throw std::runtime_error(folly::to<string>(
"received ",
data.mountPoints.size(),
" mount paths, but ",
message.files.size(),
" FDs (including the lock file FD)"));
}
data.lockFile = std::move(message.files[0]);
data.thriftSocket = std::move(message.files[1]);
for (size_t n = 0; n < data.mountPoints.size(); ++n) {
auto& mountInfo = data.mountPoints[n];
mountInfo.fuseFD = std::move(message.files[n + 2]);
}
return data;
}
} // namespace eden
} // namespace facebook
#endif