sapling/eden/fs/testharness/TestDispatcher.h
Chad Austin 6f60c48ea8 decouple ObjectFetchContext lifetime from RequestContext
Summary:
Requiring that callers ensure that ObjectFetchContext outlives the
asynchronous result is a burden and a memory-safety risk. Without
Rust's borrow checker, we can't feel confident this is safe under all
error and timeout conditions. It also requires we use
folly::collectAll and collectAllSafe, which means that an error during
fanout has to wait until the fanout completes before we can report the
error to our caller.

Moreover, tying the ObjectFetchContext's lifetime to the
FUSE/NFS/Thrift/etc. request's lifetime gives us incorrect statistics
about how long the request takes. I consider this an API design
mistake (on my part).

Correct the situation by decoupling ObjectFetchContext from
RequestContext, and begin reference-counting ObjectFetchContext.

This does increase the number of atomic RMW operations, but we can
alleviate those where they matter by manually checking
*Future::isReady() before calling .then*.

Reviewed By: xavierd

Differential Revision: D40744706

fbshipit-source-id: 5baf654f6d65790ed0cafb45c0bc7f2aaa8ecec2
2022-11-15 13:35:45 -08:00

70 lines
1.7 KiB
C++

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
#pragma once
#include <folly/Synchronized.h>
#include <folly/futures/Promise.h>
#include <chrono>
#include <condition_variable>
#include <unordered_map>
#include "eden/fs/fuse/FuseDispatcher.h"
#include "eden/fs/store/ObjectStore.h"
#include "eden/fs/utils/PathFuncs.h"
namespace facebook::eden {
/**
* A FUSE Dispatcher implementation for use in unit tests.
*
* It allows the test code to generate responses to specific requests on
* demand.
*/
class TestDispatcher : public FuseDispatcher {
public:
/**
* Data for a pending FUSE_LOOKUP request.
*/
struct PendingLookup {
PendingLookup(InodeNumber parent, PathComponentPiece name)
: parent(parent), name(name.copy()) {}
InodeNumber parent;
PathComponent name;
folly::Promise<fuse_entry_out> promise;
};
using FuseDispatcher::FuseDispatcher;
ImmediateFuture<fuse_entry_out> lookup(
uint64_t requestID,
InodeNumber parent,
PathComponentPiece name,
const ObjectFetchContextPtr& context) override;
/**
* Wait for the dispatcher to receive a FUSE_LOOKUP request with the
* specified request ID.
*
* Returns a PendingLookup object that can be used to respond to the request.
*/
PendingLookup waitForLookup(
uint64_t requestId,
std::chrono::milliseconds timeout = std::chrono::milliseconds(500));
private:
struct State {
std::unordered_map<uint64_t, PendingLookup> pendingLookups;
};
folly::Synchronized<State, std::mutex> state_;
std::condition_variable requestReceived_;
};
} // namespace facebook::eden