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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
|
2017-09-13 18:26:52 +03:00
|
|
|
#include <folly/Executor.h>
|
2016-05-12 23:43:17 +03:00
|
|
|
#include <folly/File.h>
|
2017-11-20 22:34:37 +03:00
|
|
|
#include <folly/Portability.h>
|
2016-05-12 23:43:17 +03:00
|
|
|
#include <folly/Range.h>
|
|
|
|
#include <folly/SocketAddress.h>
|
|
|
|
#include <folly/Synchronized.h>
|
2017-03-31 21:23:02 +03:00
|
|
|
#include <folly/ThreadLocal.h>
|
2016-05-12 23:43:17 +03:00
|
|
|
#include <folly/experimental/StringKeyedMap.h>
|
2017-08-01 06:48:19 +03:00
|
|
|
#include <folly/futures/SharedPromise.h>
|
2016-07-01 07:00:01 +03:00
|
|
|
#include <condition_variable>
|
2016-05-12 23:43:17 +03:00
|
|
|
#include <memory>
|
2016-07-01 07:00:01 +03:00
|
|
|
#include <mutex>
|
2016-06-14 01:15:31 +03:00
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
2016-05-12 23:43:17 +03:00
|
|
|
#include <vector>
|
2017-04-14 21:31:48 +03:00
|
|
|
#include "eden/fs/fuse/EdenStats.h"
|
2018-01-10 09:00:50 +03:00
|
|
|
#include "eden/fs/fuse/FuseTypes.h"
|
2018-01-10 09:01:00 +03:00
|
|
|
#include "eden/fs/inodes/EdenMount.h"
|
2018-02-09 03:33:32 +03:00
|
|
|
#include "eden/fs/inodes/ServerState.h"
|
2018-01-10 09:00:58 +03:00
|
|
|
#include "eden/fs/takeover/TakeoverData.h"
|
2017-11-20 02:18:29 +03:00
|
|
|
#include "eden/fs/takeover/TakeoverHandler.h"
|
2017-04-14 21:31:48 +03:00
|
|
|
#include "eden/fs/utils/PathFuncs.h"
|
2017-08-01 06:49:35 +03:00
|
|
|
#include "folly/experimental/FunctionScheduler.h"
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2017-08-25 22:41:41 +03:00
|
|
|
constexpr folly::StringPiece kPeriodicUnloadCounterKey{"PeriodicUnloadCounter"};
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
namespace apache {
|
|
|
|
namespace thrift {
|
|
|
|
class ThriftServer;
|
|
|
|
}
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace apache
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2017-09-01 04:58:48 +03:00
|
|
|
namespace folly {
|
|
|
|
class EventBase;
|
|
|
|
}
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
|
2016-06-14 01:15:31 +03:00
|
|
|
class BackingStore;
|
2016-11-26 23:00:16 +03:00
|
|
|
class Dirstate;
|
2016-05-12 23:43:17 +03:00
|
|
|
class EdenServiceHandler;
|
|
|
|
class LocalStore;
|
2017-09-13 18:26:53 +03:00
|
|
|
class MountInfo;
|
2017-11-20 02:18:29 +03:00
|
|
|
class TakeoverServer;
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* EdenServer contains logic for running the Eden main loop.
|
|
|
|
*
|
|
|
|
* It performs locking to ensure only a single EdenServer instance is running
|
|
|
|
* for a particular location, then starts the thrift management server
|
|
|
|
* and the fuse session.
|
|
|
|
*/
|
2017-11-20 02:18:29 +03:00
|
|
|
class EdenServer : private TakeoverHandler {
|
2016-05-12 23:43:17 +03:00
|
|
|
public:
|
2016-05-20 20:33:42 +03:00
|
|
|
using MountList = std::vector<std::shared_ptr<EdenMount>>;
|
2016-11-26 23:00:16 +03:00
|
|
|
using DirstateMap = folly::StringKeyedMap<std::shared_ptr<Dirstate>>;
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2016-07-26 20:15:43 +03:00
|
|
|
EdenServer(
|
2018-02-09 03:33:32 +03:00
|
|
|
UserInfo userInfo,
|
2018-02-09 06:31:59 +03:00
|
|
|
std::unique_ptr<PrivHelper> privHelper,
|
2016-12-15 23:34:39 +03:00
|
|
|
AbsolutePathPiece edenDir,
|
2017-01-24 10:52:46 +03:00
|
|
|
AbsolutePathPiece etcEdenDir,
|
2017-12-14 23:35:17 +03:00
|
|
|
AbsolutePathPiece configPath);
|
2018-01-18 00:29:59 +03:00
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
virtual ~EdenServer();
|
|
|
|
|
2017-08-30 23:43:39 +03:00
|
|
|
/**
|
|
|
|
* Run the EdenServer.
|
|
|
|
*/
|
|
|
|
void run();
|
|
|
|
|
2017-03-21 22:57:07 +03:00
|
|
|
/**
|
2017-04-14 21:31:49 +03:00
|
|
|
* Prepare to run the EdenServer.
|
2017-03-21 22:57:07 +03:00
|
|
|
*
|
2017-04-14 21:31:49 +03:00
|
|
|
* This acquires the lock on the eden directory, remounts configured mount
|
|
|
|
* points, and prepares the thrift server to run.
|
2017-03-21 22:57:07 +03:00
|
|
|
*
|
2017-04-14 21:31:49 +03:00
|
|
|
* After prepare returns the caller can call getServer()->serve() to
|
|
|
|
* run the thrift server main loop.
|
2017-03-21 22:57:07 +03:00
|
|
|
*/
|
2017-04-14 21:31:49 +03:00
|
|
|
void prepare();
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2016-06-11 00:15:26 +03:00
|
|
|
/**
|
|
|
|
* Stops this server, which includes the underlying Thrift server.
|
2017-03-21 22:57:07 +03:00
|
|
|
*
|
|
|
|
* This may be called from any thread while a call to run() is outstanding,
|
|
|
|
* and will cause run() to return.
|
2016-06-11 00:15:26 +03:00
|
|
|
*/
|
|
|
|
void stop() const;
|
|
|
|
|
2017-11-20 02:18:29 +03:00
|
|
|
/**
|
|
|
|
* Request to shutdown the server for a graceful restart operation,
|
|
|
|
* allowing a remote process to take over the existing mount points.
|
|
|
|
*
|
|
|
|
* This pauses FUSE I/O processing, writes filesystem state to disk,
|
|
|
|
* and returns the FUSE file descriptors for each mount. This allows the
|
|
|
|
* FUSE FDs to be handed off to a new eden instance so it can take over
|
|
|
|
* existing mount points with minimal disruption to other processes using the
|
|
|
|
* mounts.
|
|
|
|
*
|
|
|
|
* Returns a Future that will return a map of (mount path -> FUSE fd)
|
|
|
|
*/
|
|
|
|
folly::Future<TakeoverData> startTakeoverShutdown() override;
|
|
|
|
|
2017-03-21 22:57:07 +03:00
|
|
|
/**
|
2017-09-13 18:26:53 +03:00
|
|
|
* Mount and return an EdenMount.
|
2017-03-21 22:57:07 +03:00
|
|
|
*/
|
2017-09-13 18:26:53 +03:00
|
|
|
FOLLY_NODISCARD folly::Future<std::shared_ptr<EdenMount>> mount(
|
2018-01-11 00:01:19 +03:00
|
|
|
std::unique_ptr<ClientConfig> initialConfig,
|
|
|
|
folly::Optional<TakeoverData::MountInfo>&& optionalTakeover =
|
|
|
|
folly::none);
|
2016-05-24 07:32:12 +03:00
|
|
|
|
2018-01-10 09:00:58 +03:00
|
|
|
/**
|
|
|
|
* Takeover a mount from another eden instance
|
|
|
|
*/
|
|
|
|
FOLLY_NODISCARD folly::Future<std::shared_ptr<EdenMount>> takeoverMount(
|
|
|
|
TakeoverData::MountInfo&& takeover);
|
|
|
|
|
2017-03-21 22:57:07 +03:00
|
|
|
/**
|
|
|
|
* Unmount an EdenMount.
|
|
|
|
*/
|
2017-08-01 06:48:19 +03:00
|
|
|
FOLLY_NODISCARD folly::Future<folly::Unit> unmount(
|
|
|
|
folly::StringPiece mountPath);
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2017-03-21 22:57:07 +03:00
|
|
|
/**
|
|
|
|
* Unmount all mount points maintained by this server, and wait for them to
|
|
|
|
* be completely unmounted.
|
|
|
|
*/
|
2018-04-05 05:40:22 +03:00
|
|
|
FOLLY_NODISCARD folly::Future<folly::Unit> unmountAll();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop all mount points maintained by this server so that they can then be
|
|
|
|
* transferred to a new edenfs process to perform a graceful restart.
|
|
|
|
*/
|
|
|
|
FOLLY_NODISCARD folly::Future<TakeoverData> stopMountsForTakeover();
|
2018-01-10 09:00:50 +03:00
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
const std::shared_ptr<EdenServiceHandler>& getHandler() const {
|
|
|
|
return handler_;
|
|
|
|
}
|
|
|
|
const std::shared_ptr<apache::thrift::ThriftServer>& getServer() const {
|
|
|
|
return server_;
|
|
|
|
}
|
|
|
|
|
2016-05-20 20:33:42 +03:00
|
|
|
MountList getMountPoints() const;
|
2017-04-04 01:47:52 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Look up an EdenMount by the path where it is mounted.
|
|
|
|
*
|
|
|
|
* Throws an EdenError if no mount exists with the specified path.
|
|
|
|
*/
|
2016-05-20 20:33:42 +03:00
|
|
|
std::shared_ptr<EdenMount> getMount(folly::StringPiece mountPath) const;
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2017-04-04 01:47:52 +03:00
|
|
|
/**
|
|
|
|
* Look up an EdenMount by the path where it is mounted.
|
|
|
|
*
|
|
|
|
* Returns nullptr if no mount exists with the specified path.
|
|
|
|
*/
|
|
|
|
std::shared_ptr<EdenMount> getMountOrNull(folly::StringPiece mountPath) const;
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
std::shared_ptr<LocalStore> getLocalStore() const {
|
|
|
|
return localStore_;
|
|
|
|
}
|
|
|
|
|
2016-06-14 01:15:31 +03:00
|
|
|
/**
|
|
|
|
* Look up the BackingStore object for the specified repository type+name.
|
|
|
|
*
|
|
|
|
* EdenServer maintains an internal cache of all known BackingStores,
|
|
|
|
* so that multiple mount points that use the same repository can
|
|
|
|
* share the same BackingStore object.
|
|
|
|
*
|
|
|
|
* If this is the first time this given (type, name) has been used, a new
|
|
|
|
* BackingStore object will be created and returned. Otherwise this will
|
|
|
|
* return the existing BackingStore that was previously created.
|
|
|
|
*/
|
|
|
|
std::shared_ptr<BackingStore> getBackingStore(
|
|
|
|
folly::StringPiece type,
|
|
|
|
folly::StringPiece name);
|
|
|
|
|
2016-11-26 23:00:16 +03:00
|
|
|
AbsolutePathPiece getEdenDir() {
|
|
|
|
return edenDir_;
|
|
|
|
}
|
|
|
|
|
2018-04-23 23:10:31 +03:00
|
|
|
const std::shared_ptr<ServerState>& getServerState() {
|
|
|
|
return serverState_;
|
2018-02-09 03:33:32 +03:00
|
|
|
}
|
2018-03-20 03:01:15 +03:00
|
|
|
ThreadLocalEdenStats* getStats() {
|
2018-04-23 23:10:31 +03:00
|
|
|
return &serverState_->getStats();
|
2017-03-31 21:23:02 +03:00
|
|
|
}
|
|
|
|
|
2017-08-18 21:43:57 +03:00
|
|
|
/**
|
|
|
|
* Flush all thread-local stats to the main ServiceData object.
|
|
|
|
*
|
|
|
|
* Thread-local counters are normally flushed to the main ServiceData once
|
|
|
|
* a second. flushStatsNow() can be used to flush thread-local counters on
|
|
|
|
* demand, in addition to the normal once-a-second flush.
|
|
|
|
*
|
|
|
|
* This is mainly useful for unit and integration tests that want to ensure
|
|
|
|
* they see up-to-date counter information without waiting for the normal
|
|
|
|
* flush interval.
|
|
|
|
*/
|
2018-02-09 03:33:32 +03:00
|
|
|
void flushStatsNow();
|
2017-08-18 21:43:57 +03:00
|
|
|
|
2017-09-01 04:58:48 +03:00
|
|
|
/**
|
|
|
|
* Get the main thread's EventBase.
|
|
|
|
*
|
|
|
|
* Callers can use this for scheduling work to be run in the main thread.
|
|
|
|
*/
|
|
|
|
folly::EventBase* getMainEventBase() const {
|
|
|
|
return mainEventBase_;
|
|
|
|
}
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
private:
|
2017-08-01 06:48:19 +03:00
|
|
|
// Struct to store EdenMount along with SharedPromise that is set
|
2017-12-12 05:01:15 +03:00
|
|
|
// during unmount to allow synchronization between unmountFinished
|
2017-08-01 06:48:19 +03:00
|
|
|
// and unmount functions.
|
|
|
|
struct EdenMountInfo {
|
|
|
|
std::shared_ptr<EdenMount> edenMount;
|
|
|
|
folly::SharedPromise<folly::Unit> unmountPromise;
|
2018-01-10 09:01:00 +03:00
|
|
|
folly::Optional<folly::Promise<TakeoverData::MountInfo>> takeoverPromise;
|
2017-08-01 06:48:19 +03:00
|
|
|
|
|
|
|
explicit EdenMountInfo(const std::shared_ptr<EdenMount>& mount)
|
|
|
|
: edenMount(mount),
|
|
|
|
unmountPromise(folly::SharedPromise<folly::Unit>()) {}
|
|
|
|
};
|
|
|
|
|
2016-06-14 01:15:31 +03:00
|
|
|
using BackingStoreKey = std::pair<std::string, std::string>;
|
|
|
|
using BackingStoreMap =
|
|
|
|
std::unordered_map<BackingStoreKey, std::shared_ptr<BackingStore>>;
|
2017-08-01 06:48:19 +03:00
|
|
|
using MountMap = folly::StringKeyedMap<struct EdenMountInfo>;
|
2017-06-27 05:27:34 +03:00
|
|
|
class ThriftServerEventHandler;
|
2016-06-14 01:15:31 +03:00
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
// Forbidden copy constructor and assignment operator
|
|
|
|
EdenServer(EdenServer const&) = delete;
|
|
|
|
EdenServer& operator=(EdenServer const&) = delete;
|
|
|
|
|
2017-09-13 18:26:50 +03:00
|
|
|
// Schedules a timer to flush stats (and reschedule itself).
|
|
|
|
// We should have at most one of these pending at a time.
|
|
|
|
// Must be called only from the eventBase thread.
|
|
|
|
void scheduleFlushStats();
|
|
|
|
|
|
|
|
// Schedule a call to unloadInodes() to happen after timeout
|
|
|
|
// has expired.
|
|
|
|
// Must be called only from the eventBase thread.
|
|
|
|
void scheduleInodeUnload(std::chrono::milliseconds timeout);
|
|
|
|
|
|
|
|
// Perform unloading of inodes based on their last access time
|
|
|
|
// and then schedule another call to unloadInodes() to happen
|
|
|
|
// at the next appropriate interval. The unload attempt applies to
|
|
|
|
// all mounts.
|
|
|
|
void unloadInodes();
|
|
|
|
|
2016-06-14 01:15:31 +03:00
|
|
|
std::shared_ptr<BackingStore> createBackingStore(
|
|
|
|
folly::StringPiece type,
|
|
|
|
folly::StringPiece name);
|
2016-05-12 23:43:17 +03:00
|
|
|
void createThriftServer();
|
2017-11-20 22:34:37 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Acquire the main edenfs lock.
|
|
|
|
*
|
|
|
|
* Returns true if the lock was acquired successfully, or false if we failed
|
|
|
|
* to acquire the lock (likely due to another process holding it).
|
|
|
|
* May throw an exception on other errors (e.g., insufficient permissions to
|
|
|
|
* create the lock file, out of disk space, etc).
|
|
|
|
*/
|
|
|
|
FOLLY_NODISCARD bool acquireEdenLock();
|
|
|
|
|
2016-05-12 23:43:17 +03:00
|
|
|
void prepareThriftAddress();
|
|
|
|
|
2016-05-20 20:33:42 +03:00
|
|
|
// Called when a mount has been unmounted and has stopped.
|
2018-01-10 09:00:50 +03:00
|
|
|
void mountFinished(
|
|
|
|
EdenMount* mountPoint,
|
2018-01-10 09:01:00 +03:00
|
|
|
folly::Optional<TakeoverData::MountInfo> takeover);
|
2016-05-12 23:43:17 +03:00
|
|
|
|
2018-01-11 00:01:19 +03:00
|
|
|
FOLLY_NODISCARD folly::Future<folly::Unit> performNormalShutdown();
|
|
|
|
FOLLY_NODISCARD folly::Future<folly::Unit> performTakeoverShutdown(
|
|
|
|
folly::File thriftSocket);
|
2017-11-20 02:18:29 +03:00
|
|
|
void shutdownPrivhelper();
|
2017-08-01 06:49:35 +03:00
|
|
|
|
2018-01-11 00:01:19 +03:00
|
|
|
// Starts up a new fuse mount for edenMount, starting up the thread
|
|
|
|
// pool and initializing the fuse session
|
|
|
|
FOLLY_NODISCARD folly::Future<folly::Unit> performFreshFuseStart(
|
|
|
|
std::shared_ptr<EdenMount> edenMount);
|
|
|
|
|
|
|
|
// Performs a takeover initialization for the provided fuse mount,
|
|
|
|
// loading the state from the old incarnation and starting up the
|
|
|
|
// thread pool.
|
|
|
|
FOLLY_NODISCARD folly::Future<folly::Unit> performTakeoverFuseStart(
|
|
|
|
std::shared_ptr<EdenMount> edenMount,
|
|
|
|
TakeoverData::MountInfo&& takeover);
|
|
|
|
|
2017-09-13 18:26:53 +03:00
|
|
|
// Add the mount point to mountPoints_.
|
|
|
|
// This also makes sure we don't have this path mounted already.
|
|
|
|
void addToMountPoints(std::shared_ptr<EdenMount> edenMount);
|
|
|
|
|
|
|
|
// Registers (or removes) stats callbacks for edenMount.
|
|
|
|
// These are here rather than in EdenMount because we need to
|
|
|
|
// hold an owning reference to the mount to safely sample stats.
|
|
|
|
void registerStats(std::shared_ptr<EdenMount> edenMount);
|
|
|
|
void unregisterStats(EdenMount* edenMount);
|
|
|
|
|
2018-01-11 00:01:22 +03:00
|
|
|
// Cancel all subscribers on all mounts so that we can tear
|
|
|
|
// down the thrift server without blocking
|
|
|
|
void shutdownSubscribers() const;
|
|
|
|
|
2016-06-20 21:43:45 +03:00
|
|
|
/*
|
|
|
|
* Member variables.
|
|
|
|
*
|
|
|
|
* Note that the declaration order below is important for initialization
|
|
|
|
* and cleanup order. lockFile_ is near the top so it will be released last.
|
|
|
|
* mountPoints_ are near the bottom, so they get destroyed before the
|
|
|
|
* backingStores_ and localStore_.
|
|
|
|
*/
|
|
|
|
|
2016-11-26 23:00:16 +03:00
|
|
|
AbsolutePath edenDir_;
|
2017-01-24 10:52:46 +03:00
|
|
|
AbsolutePath etcEdenDir_;
|
2016-08-05 22:49:25 +03:00
|
|
|
AbsolutePath configPath_;
|
2016-06-20 21:43:45 +03:00
|
|
|
folly::File lockFile_;
|
2016-05-12 23:43:17 +03:00
|
|
|
std::shared_ptr<EdenServiceHandler> handler_;
|
|
|
|
std::shared_ptr<apache::thrift::ThriftServer> server_;
|
2017-06-27 05:27:34 +03:00
|
|
|
std::shared_ptr<ThriftServerEventHandler> serverEventHandler_;
|
2016-05-12 23:43:17 +03:00
|
|
|
|
|
|
|
std::shared_ptr<LocalStore> localStore_;
|
2016-06-14 01:15:31 +03:00
|
|
|
folly::Synchronized<BackingStoreMap> backingStores_;
|
2016-07-01 07:00:01 +03:00
|
|
|
|
2017-08-03 03:40:57 +03:00
|
|
|
folly::Synchronized<MountMap> mountPoints_;
|
2017-08-01 06:49:35 +03:00
|
|
|
|
2017-11-20 02:18:29 +03:00
|
|
|
/**
|
|
|
|
* A server that waits on a new edenfs process to attempt
|
|
|
|
* a graceful restart, taking over our running mount points.
|
|
|
|
*/
|
|
|
|
std::unique_ptr<TakeoverServer> takeoverServer_;
|
|
|
|
folly::Promise<TakeoverData> takeoverPromise_;
|
|
|
|
|
2018-02-09 06:32:01 +03:00
|
|
|
enum class RunState {
|
2017-11-20 02:18:29 +03:00
|
|
|
STARTING,
|
|
|
|
RUNNING,
|
|
|
|
SHUTTING_DOWN,
|
|
|
|
};
|
2018-02-09 06:32:01 +03:00
|
|
|
/**
|
|
|
|
* Information about whether the EdenServer is starting, running, or shutting
|
|
|
|
* down, including whether it is performing a graceful restart.
|
|
|
|
*/
|
|
|
|
struct RunStateData {
|
|
|
|
RunState state{RunState::STARTING};
|
2017-11-20 02:18:29 +03:00
|
|
|
bool takeoverShutdown{false};
|
2017-11-20 02:18:31 +03:00
|
|
|
folly::File takeoverThriftSocket;
|
2017-11-20 02:18:29 +03:00
|
|
|
};
|
2018-02-09 06:32:01 +03:00
|
|
|
folly::Synchronized<RunStateData> runningState_;
|
2017-11-20 02:18:29 +03:00
|
|
|
|
2018-02-09 03:33:32 +03:00
|
|
|
/**
|
|
|
|
* Common state shared by all of the EdenMount objects.
|
|
|
|
*/
|
2018-04-23 23:10:31 +03:00
|
|
|
std::shared_ptr<ServerState> serverState_;
|
2018-02-09 03:33:32 +03:00
|
|
|
|
2017-09-01 04:58:48 +03:00
|
|
|
/**
|
|
|
|
* The EventBase driving the main thread loop.
|
|
|
|
*
|
|
|
|
* This is used to drive the the thrift server and can also be used for
|
|
|
|
* scheduling other asynchronous operations.
|
|
|
|
*
|
|
|
|
* This is set when the EdenServer is started and is never updated after
|
|
|
|
* this, so we do not need synchronization when reading it.
|
|
|
|
*/
|
|
|
|
folly::EventBase* mainEventBase_;
|
2016-05-12 23:43:17 +03:00
|
|
|
};
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace eden
|
|
|
|
} // namespace facebook
|