sapling/eden/fs/journal/Journal.h
Wez Furlong d3202383c1 tidy up journal subscribers on unmount
Summary:
We have a couple of issues with the watchman/eden integration:

1. If you "win" the race, you can cause a segfault during shutdown
by changing files during unmount.  This causes the journal updating
code to trigger a send to the client, but the associated eventBase
has already been destroyed.

2. We don't proactively send any signal to the subscriber (in practice: watchman)
when we unmount.  Watchman detects the eden shutdown by noticing that its
socket has closed but has no way to detect an unmount.

This diff tries to connect the unmount with the set of subscribers and tries
to cause the thrift socket to close out.

Reviewed By: bolinfest

Differential Revision: D6162717

fbshipit-source-id: 42d4a005089cd9cddf204997b1643570488f04c3
2017-10-27 09:01:57 -07:00

87 lines
3.0 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/Function.h>
#include <cstdint>
#include <memory>
#include <unordered_map>
namespace facebook {
namespace eden {
class JournalDelta;
/** The Journal exists to answer questions about how files are changing
* over time.
*
* It contains metadata only; it is not a full snapshot of the state of
* the filesystem at a particular point in time.
* The intent is to be able query things like "which set of files changed
* between time A and time B?".
*
* In the initial implementation we are recording file names from the overlay
* but will expand this to record things like checking out different
* revisions (the prior and new revision hash) from which we can derive
* the larger list of files.
*
* The Journal class is not internally threadsafe; we make it safe
* through the use of folly::Synchronized in the EdenMount class
* that owns the Journal.
*/
class Journal {
public:
using SequenceNumber = uint64_t;
/** Add a delta to the journal
* The delta will have a new sequence number and timestamp
* applied. */
void addDelta(std::unique_ptr<JournalDelta>&& delta);
/** Get a shared, immutable reference to the tip of the journal.
* May return nullptr if there have been no changes */
std::shared_ptr<const JournalDelta> getLatest() const;
/** Replace the journal with a new delta.
* The new delta will typically be the result of JournalDelta::merge().
* No sanity checking is performed inside this function; the
* supplied delta is moved in and replaces current tip. */
void replaceJournal(std::unique_ptr<JournalDelta>&& delta);
/** Register a subscriber.
* A subscriber is just a callback that is called whenever the
* journal has changed.
* It is recommended that the subscriber callback do the minimal
* amount of work needed to schedule the real work to happen in
* some other context because journal updates are likely to happen
* in awkward contexts or in the middle of some batch of mutations
* where it is not appropriate to do any heavy lifting.
* The return value of registerSubscriber is an identifier than
* can be passed to cancelSubscriber to later remove the registration.
*/
uint64_t registerSubscriber(folly::Function<void()>&& callback);
void cancelSubscriber(uint64_t id);
void cancelAllSubscribers();
bool isSubscriberValid(uint64_t id) const;
private:
/** The sequence number that we'll use for the next entry
* that we link into the chain */
SequenceNumber nextSequence_{1};
/** The most recently recorded entry */
std::shared_ptr<const JournalDelta> latest_;
/** The next id to assign to subscribers */
uint64_t nextSubscriberId_{1};
/** The subscribers */
std::unordered_map<uint64_t, folly::Function<void()>> subscribers_;
};
}
}