2016-09-19 22:48:10 +03:00
|
|
|
/*
|
2017-01-21 09:02:33 +03:00
|
|
|
* Copyright (c) 2016-present, Facebook, Inc.
|
2016-09-19 22:48:10 +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
|
2018-08-18 07:04:07 +03:00
|
|
|
|
2017-03-21 23:25:30 +03:00
|
|
|
#include <folly/Function.h>
|
2017-11-11 06:49:58 +03:00
|
|
|
#include <folly/Synchronized.h>
|
2019-06-01 00:36:54 +03:00
|
|
|
#include <algorithm>
|
2016-09-19 22:48:10 +03:00
|
|
|
#include <cstdint>
|
|
|
|
#include <memory>
|
2019-06-01 00:36:54 +03:00
|
|
|
#include <optional>
|
2017-03-21 23:25:30 +03:00
|
|
|
#include <unordered_map>
|
2018-08-18 07:04:07 +03:00
|
|
|
#include "eden/fs/journal/JournalDelta.h"
|
2016-09-19 22:48:10 +03:00
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
|
2019-06-01 00:36:54 +03:00
|
|
|
/** Contains statistics about the current state of the journal */
|
|
|
|
struct JournalStats {
|
2019-06-07 23:33:49 +03:00
|
|
|
size_t entryCount = 0;
|
|
|
|
size_t memoryUsage = 0;
|
2019-06-01 00:36:54 +03:00
|
|
|
std::chrono::steady_clock::time_point earliestTimestamp;
|
|
|
|
std::chrono::steady_clock::time_point latestTimestamp;
|
|
|
|
};
|
|
|
|
|
2016-09-19 22:48:10 +03:00
|
|
|
/** 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.
|
|
|
|
*
|
2017-11-11 06:49:58 +03:00
|
|
|
* The Journal class is thread-safe. Subscribers are called on the thread
|
|
|
|
* that called addDelta.
|
2016-09-19 22:48:10 +03:00
|
|
|
*/
|
|
|
|
class Journal {
|
|
|
|
public:
|
2018-08-16 00:43:28 +03:00
|
|
|
Journal() = default;
|
|
|
|
|
|
|
|
/// It is almost always a mistake to copy a Journal.
|
|
|
|
Journal(const Journal&) = delete;
|
|
|
|
Journal& operator=(const Journal&) = delete;
|
|
|
|
|
2018-08-18 07:04:07 +03:00
|
|
|
using SequenceNumber = JournalDelta::SequenceNumber;
|
2017-11-11 06:49:58 +03:00
|
|
|
using SubscriberId = uint64_t;
|
|
|
|
using SubscriberCallback = std::function<void()>;
|
2016-09-19 22:48:10 +03:00
|
|
|
|
|
|
|
/** 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 */
|
2018-08-18 07:04:07 +03:00
|
|
|
JournalDeltaPtr getLatest() const;
|
2016-09-19 22:48:10 +03:00
|
|
|
|
2017-03-21 23:25:30 +03:00
|
|
|
/** 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.
|
|
|
|
*/
|
2017-11-11 06:49:58 +03:00
|
|
|
SubscriberId registerSubscriber(SubscriberCallback&& callback);
|
|
|
|
void cancelSubscriber(SubscriberId id);
|
2017-03-21 23:25:30 +03:00
|
|
|
|
2017-10-27 18:44:19 +03:00
|
|
|
void cancelAllSubscribers();
|
2017-11-11 06:49:58 +03:00
|
|
|
bool isSubscriberValid(SubscriberId id) const;
|
2017-10-27 18:44:19 +03:00
|
|
|
|
2019-06-01 00:36:54 +03:00
|
|
|
/** Returns an option that is nullopt if the Journal is empty or an option
|
|
|
|
* that contains valid JournalStats if the Journal is non-empty*/
|
|
|
|
std::optional<JournalStats> getStats();
|
|
|
|
|
2016-09-19 22:48:10 +03:00
|
|
|
private:
|
2017-11-11 06:49:58 +03:00
|
|
|
struct DeltaState {
|
|
|
|
/** 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 */
|
2018-08-18 07:04:07 +03:00
|
|
|
JournalDeltaPtr latest;
|
2019-06-07 23:33:49 +03:00
|
|
|
/** The stats about this Journal up to the latest delta */
|
|
|
|
std::optional<JournalStats> stats;
|
2017-11-11 06:49:58 +03:00
|
|
|
};
|
|
|
|
folly::Synchronized<DeltaState> deltaState_;
|
|
|
|
|
|
|
|
struct SubscriberState {
|
|
|
|
SubscriberId nextSubscriberId{1};
|
|
|
|
std::unordered_map<SubscriberId, SubscriberCallback> subscribers;
|
|
|
|
};
|
|
|
|
|
|
|
|
folly::Synchronized<SubscriberState> subscriberState_;
|
2016-09-19 22:48:10 +03:00
|
|
|
};
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace eden
|
|
|
|
} // namespace facebook
|