added JournalStats

Summary: Added JournalStats to start tracking basic stats on the Journal

Reviewed By: chadaustin

Differential Revision: D15565886

fbshipit-source-id: b7345df377303fc442ecf4c112afa7493bb2dc28
This commit is contained in:
Jake Crouch 2019-05-31 14:36:54 -07:00 committed by Facebook Github Bot
parent e8daac0e33
commit 5a59af8ae9
3 changed files with 114 additions and 0 deletions

View File

@ -87,5 +87,23 @@ bool Journal::isSubscriberValid(uint64_t id) const {
return subscribers.find(id) != subscribers.end();
}
std::optional<JournalStats> Journal::getStats() {
JournalStats stats;
auto curr = getLatest();
if (curr == nullptr) {
// return None since this is an empty journal
return std::nullopt;
}
stats.latestTimestamp = curr->toTime;
stats.earliestTimestamp = curr->fromTime;
while (curr != nullptr) {
++stats.entryCount;
stats.latestTimestamp = std::max(stats.latestTimestamp, curr->toTime);
stats.earliestTimestamp = std::min(stats.earliestTimestamp, curr->fromTime);
curr = curr->previous;
}
return stats;
}
} // namespace eden
} // namespace facebook

View File

@ -11,14 +11,23 @@
#include <folly/Function.h>
#include <folly/Synchronized.h>
#include <algorithm>
#include <cstdint>
#include <memory>
#include <optional>
#include <unordered_map>
#include "eden/fs/journal/JournalDelta.h"
namespace facebook {
namespace eden {
/** Contains statistics about the current state of the journal */
struct JournalStats {
uint64_t entryCount = 0;
std::chrono::steady_clock::time_point earliestTimestamp;
std::chrono::steady_clock::time_point latestTimestamp;
};
/** The Journal exists to answer questions about how files are changing
* over time.
*
@ -79,6 +88,10 @@ class Journal {
void cancelAllSubscribers();
bool isSubscriberValid(SubscriberId id) const;
/** 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();
private:
struct DeltaState {
/** The sequence number that we'll use for the next entry

View File

@ -171,3 +171,86 @@ TEST(Journal, destruction_does_not_overflow_stack_on_long_chain) {
journal.addDelta(std::move(delta));
}
}
TEST(Journal, empty_journal_returns_none_for_stats) {
// Empty journal returns None for stats
Journal journal;
auto stats = journal.getStats();
ASSERT_FALSE(stats.has_value());
}
TEST(Journal, basic_journal_stats) {
Journal journal;
// Journal with 1 entry
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::REMOVED));
auto from1 = journal.getLatest()->fromTime;
auto to1 = journal.getLatest()->toTime;
auto stats = journal.getStats();
ASSERT_TRUE(stats.has_value());
ASSERT_EQ(1, stats->entryCount);
ASSERT_EQ(from1, stats->earliestTimestamp);
ASSERT_EQ(to1, stats->latestTimestamp);
// Journal with 2 entries
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::CREATED));
stats = journal.getStats();
auto to2 = journal.getLatest()->toTime;
ASSERT_TRUE(stats.has_value());
ASSERT_EQ(2, stats->entryCount);
ASSERT_EQ(from1, stats->earliestTimestamp);
ASSERT_EQ(to2, stats->latestTimestamp);
}
TEST(Journal, merge_journal_stats) {
Journal journal;
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::REMOVED));
auto from1 = journal.getLatest()->fromTime;
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::CREATED));
auto stats = journal.getStats();
auto to2 = journal.getLatest()->toTime;
// Journal with 2 entries merged into 1 entry
auto latest = journal.getLatest();
journal.replaceJournal(latest->merge());
stats = journal.getStats();
ASSERT_TRUE(stats.has_value());
ASSERT_EQ(1, stats->entryCount);
ASSERT_EQ(from1, stats->earliestTimestamp);
ASSERT_EQ(to2, stats->latestTimestamp);
}
TEST(Journal, prune_journal_stats) {
Journal journal;
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::REMOVED));
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::CREATED));
auto stats = journal.getStats();
auto from2 = journal.getLatest()->fromTime;
auto to2 = journal.getLatest()->toTime;
auto latest = journal.getLatest();
// Journal with the first entry pruned
journal.replaceJournal(latest->merge(2, true));
stats = journal.getStats();
ASSERT_TRUE(stats.has_value());
ASSERT_EQ(1, stats->entryCount);
ASSERT_EQ(from2, stats->earliestTimestamp);
ASSERT_EQ(to2, stats->latestTimestamp);
}
TEST(Journal, fully_pruned_journal_stats) {
Journal journal;
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::REMOVED));
journal.addDelta(std::make_unique<JournalDelta>(
"test.txt"_relpath, JournalDelta::CREATED));
auto latest = journal.getLatest();
// Journal with all entries pruned
journal.replaceJournal(latest->merge(3, true));
auto stats = journal.getStats();
ASSERT_FALSE(stats.has_value());
}