2016-09-19 22:48:10 +03:00
|
|
|
/*
|
2019-06-20 02:58:25 +03:00
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
2016-09-19 22:48:10 +03:00
|
|
|
*
|
2019-06-20 02:58:25 +03:00
|
|
|
* This software may be used and distributed according to the terms of the
|
|
|
|
* GNU General Public License version 2.
|
2016-09-19 22:48:10 +03:00
|
|
|
*/
|
2019-10-11 15:26:59 +03:00
|
|
|
|
2016-09-19 22:48:10 +03:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <chrono>
|
2019-08-03 01:42:50 +03:00
|
|
|
#include <type_traits>
|
2016-09-19 22:48:10 +03:00
|
|
|
#include <unordered_set>
|
2019-08-03 01:42:50 +03:00
|
|
|
#include <variant>
|
2016-09-19 22:48:12 +03:00
|
|
|
#include "eden/fs/model/Hash.h"
|
2017-04-14 21:31:48 +03:00
|
|
|
#include "eden/fs/utils/PathFuncs.h"
|
2016-09-19 22:48:10 +03:00
|
|
|
|
|
|
|
namespace facebook {
|
|
|
|
namespace eden {
|
|
|
|
|
2018-08-16 00:43:28 +03:00
|
|
|
struct PathChangeInfo {
|
|
|
|
PathChangeInfo() : existedBefore{false}, existedAfter{false} {}
|
|
|
|
|
|
|
|
PathChangeInfo(bool before, bool after)
|
|
|
|
: existedBefore{before}, existedAfter{after} {}
|
|
|
|
|
|
|
|
bool isNew() const {
|
|
|
|
return !existedBefore && existedAfter;
|
|
|
|
}
|
|
|
|
|
2019-07-25 03:27:47 +03:00
|
|
|
bool operator==(const PathChangeInfo& other) const {
|
|
|
|
return existedBefore == other.existedBefore &&
|
|
|
|
existedAfter == other.existedAfter;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const PathChangeInfo& other) const {
|
|
|
|
return !(*this == other);
|
|
|
|
}
|
|
|
|
|
2018-08-16 00:43:28 +03:00
|
|
|
/// Whether this path existed at the start of this delta.
|
|
|
|
bool existedBefore : 1;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether this path existed at the end of this delta.
|
|
|
|
* If existedAfter && !existedBefore, then the file can be considered new in
|
|
|
|
* this delta.
|
|
|
|
*/
|
|
|
|
bool existedAfter : 1;
|
|
|
|
|
|
|
|
// TODO: It may make sense to maintain an existenceChanged bit to distinguish
|
|
|
|
// between a file being changed and it being removed and added in the same
|
|
|
|
// delta.
|
|
|
|
};
|
|
|
|
|
2016-09-19 22:48:10 +03:00
|
|
|
class JournalDelta {
|
|
|
|
public:
|
2018-08-18 07:04:07 +03:00
|
|
|
using SequenceNumber = uint64_t;
|
|
|
|
|
2019-08-03 01:42:50 +03:00
|
|
|
/** The ID of this Delta in the Journal */
|
|
|
|
JournalDelta::SequenceNumber sequenceID;
|
|
|
|
/** The time at which the change was recorded. */
|
|
|
|
std::chrono::steady_clock::time_point time;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** A delta that stores information about changed files */
|
|
|
|
class FileChangeJournalDelta : public JournalDelta {
|
|
|
|
public:
|
2017-08-11 22:51:51 +03:00
|
|
|
enum Created { CREATED };
|
|
|
|
enum Removed { REMOVED };
|
2018-08-16 00:43:28 +03:00
|
|
|
enum Changed { CHANGED };
|
2019-06-20 01:12:50 +03:00
|
|
|
enum Renamed { RENAMED };
|
|
|
|
enum Replaced { REPLACED };
|
2019-08-03 01:42:50 +03:00
|
|
|
|
|
|
|
FileChangeJournalDelta() = default;
|
|
|
|
FileChangeJournalDelta(FileChangeJournalDelta&&) = default;
|
|
|
|
FileChangeJournalDelta& operator=(FileChangeJournalDelta&&) = default;
|
|
|
|
FileChangeJournalDelta(const FileChangeJournalDelta&) = delete;
|
|
|
|
FileChangeJournalDelta& operator=(const FileChangeJournalDelta&) = delete;
|
|
|
|
FileChangeJournalDelta(RelativePathPiece fileName, Created);
|
|
|
|
FileChangeJournalDelta(RelativePathPiece fileName, Removed);
|
|
|
|
FileChangeJournalDelta(RelativePathPiece fileName, Changed);
|
2018-08-18 07:04:07 +03:00
|
|
|
|
2018-05-08 00:15:45 +03:00
|
|
|
/**
|
|
|
|
* "Renamed" means that that newName was created as a result of the mv(1).
|
|
|
|
*/
|
2019-08-03 01:42:50 +03:00
|
|
|
FileChangeJournalDelta(
|
|
|
|
RelativePathPiece oldName,
|
|
|
|
RelativePathPiece newName,
|
|
|
|
Renamed);
|
2016-09-19 22:48:11 +03:00
|
|
|
|
2018-05-08 00:15:45 +03:00
|
|
|
/**
|
|
|
|
* "Replaced" means that that newName was overwritten by oldName as a result
|
|
|
|
* of the mv(1).
|
|
|
|
*/
|
2019-08-03 01:42:50 +03:00
|
|
|
FileChangeJournalDelta(
|
|
|
|
RelativePathPiece oldName,
|
|
|
|
RelativePathPiece newName,
|
|
|
|
Replaced);
|
2016-09-19 22:48:12 +03:00
|
|
|
|
2019-06-21 00:22:26 +03:00
|
|
|
/** Which of these paths actually contain information */
|
|
|
|
RelativePath path1;
|
|
|
|
RelativePath path2;
|
|
|
|
PathChangeInfo info1;
|
|
|
|
PathChangeInfo info2;
|
|
|
|
bool isPath1Valid = false;
|
|
|
|
bool isPath2Valid = false;
|
|
|
|
|
|
|
|
std::unordered_map<RelativePath, PathChangeInfo> getChangedFilesInOverlay()
|
|
|
|
const;
|
|
|
|
|
2019-08-03 01:42:50 +03:00
|
|
|
/** Checks whether this delta is a modification */
|
|
|
|
bool isModification() const;
|
|
|
|
|
|
|
|
/** Checks whether this delta and other are the same disregarding time and
|
|
|
|
* sequenceID [whether they do the same action] */
|
|
|
|
bool isSameAction(const FileChangeJournalDelta& other) const;
|
|
|
|
|
|
|
|
/** Get memory used (in bytes) by this Delta */
|
|
|
|
size_t estimateMemoryUsage() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** A delta that stores information about changing commits */
|
|
|
|
class HashUpdateJournalDelta : public JournalDelta {
|
|
|
|
public:
|
|
|
|
HashUpdateJournalDelta() = default;
|
|
|
|
HashUpdateJournalDelta(HashUpdateJournalDelta&&) = default;
|
|
|
|
HashUpdateJournalDelta& operator=(HashUpdateJournalDelta&&) = default;
|
|
|
|
HashUpdateJournalDelta(const HashUpdateJournalDelta&) = delete;
|
|
|
|
HashUpdateJournalDelta& operator=(const HashUpdateJournalDelta&) = delete;
|
|
|
|
|
|
|
|
/** The snapshot hash that we started and ended up on.
|
|
|
|
* This will often be the same unless we perform a checkout or make
|
|
|
|
* a new snapshot from the snapshotable files in the overlay. */
|
|
|
|
Hash fromHash;
|
|
|
|
|
2017-10-17 08:22:18 +03:00
|
|
|
/** The set of files that had differing status across a checkout or
|
|
|
|
* some other operation that changes the snapshot hash */
|
|
|
|
std::unordered_set<RelativePath> uncleanPaths;
|
2016-09-19 22:48:10 +03:00
|
|
|
|
2019-06-07 23:33:49 +03:00
|
|
|
/** Get memory used (in bytes) by this Delta */
|
|
|
|
size_t estimateMemoryUsage() const;
|
2019-08-03 01:42:50 +03:00
|
|
|
};
|
2019-06-07 23:33:49 +03:00
|
|
|
|
2019-08-03 01:42:50 +03:00
|
|
|
class JournalDeltaPtr {
|
|
|
|
public:
|
|
|
|
/* implicit */ JournalDeltaPtr(std::nullptr_t);
|
2019-07-25 03:27:47 +03:00
|
|
|
|
2019-08-03 01:42:50 +03:00
|
|
|
/* implicit */ JournalDeltaPtr(FileChangeJournalDelta* p);
|
|
|
|
|
|
|
|
/* implicit */ JournalDeltaPtr(HashUpdateJournalDelta* p);
|
|
|
|
|
|
|
|
size_t estimateMemoryUsage() const;
|
|
|
|
|
|
|
|
explicit operator bool() const noexcept {
|
|
|
|
return !std::holds_alternative<std::monostate>(data_);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** If this JournalDeltaPtr points to a FileChangeJournalDelta then returns
|
|
|
|
* the raw pointer, if it does not point to a FileChangeJournalDelta then
|
|
|
|
* return nullptr. */
|
|
|
|
FileChangeJournalDelta* getAsFileChangeJournalDelta();
|
|
|
|
|
|
|
|
const JournalDelta* operator->() const noexcept;
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::variant<std::monostate, FileChangeJournalDelta*, HashUpdateJournalDelta*>
|
|
|
|
data_;
|
2016-09-19 22:48:10 +03:00
|
|
|
};
|
2018-08-18 07:04:07 +03:00
|
|
|
|
2019-06-20 01:12:50 +03:00
|
|
|
struct JournalDeltaRange {
|
|
|
|
/** The current sequence range.
|
|
|
|
* This is a range to accommodate merging a range into a single entry. */
|
|
|
|
JournalDelta::SequenceNumber fromSequence;
|
|
|
|
JournalDelta::SequenceNumber toSequence;
|
|
|
|
/** The time at which the change was recorded.
|
|
|
|
* This is a range to accommodate merging a range into a single entry. */
|
|
|
|
std::chrono::steady_clock::time_point fromTime;
|
|
|
|
std::chrono::steady_clock::time_point toTime;
|
|
|
|
|
|
|
|
/** The snapshot hash that we started and ended up on.
|
|
|
|
* This will often be the same unless we perform a checkout or make
|
|
|
|
* a new snapshot from the snapshotable files in the overlay. */
|
|
|
|
Hash fromHash;
|
|
|
|
Hash toHash;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The set of files that changed in the overlay in this update, including
|
|
|
|
* some information about the changes.
|
|
|
|
*/
|
|
|
|
std::unordered_map<RelativePath, PathChangeInfo> changedFilesInOverlay;
|
|
|
|
/** The set of files that had differing status across a checkout or
|
|
|
|
* some other operation that changes the snapshot hash */
|
|
|
|
std::unordered_set<RelativePath> uncleanPaths;
|
|
|
|
|
|
|
|
bool isTruncated = false;
|
|
|
|
JournalDeltaRange() = default;
|
|
|
|
JournalDeltaRange(JournalDeltaRange&&) = default;
|
|
|
|
JournalDeltaRange& operator=(JournalDeltaRange&&) = default;
|
|
|
|
};
|
|
|
|
|
2017-11-04 01:58:04 +03:00
|
|
|
} // namespace eden
|
|
|
|
} // namespace facebook
|