blob: 22e0cbfe4f9bb67e15e1f5444cd695de4bf743fe [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_STORAGE_LIB_VFS_CPP_JOURNAL_REPLAY_TREE_H_
#define SRC_STORAGE_LIB_VFS_CPP_JOURNAL_REPLAY_TREE_H_
#include <range/interval-tree.h>
#include <range/range.h>
#include <storage/operation/operation.h>
namespace fs {
namespace internal {
// Container for BufferedOperations collected during replay.
//
// The "dev_offset" is used as a key for determining overlap.
class RangeContainer {
public:
explicit RangeContainer(storage::BufferedOperation op) : operation(std::move(op)) {}
uint64_t Start() const { return operation.op.dev_offset; }
uint64_t End() const { return operation.op.dev_offset + operation.op.length; }
void Update(uint64_t start, uint64_t end) {
// update is called during range merges and splits. during these operations, vmo_offset stays a
// constant distance away from dev_offset. calculate the movement of dev_offset in this
// operation and move vmo_offset accordingly.
int64_t diff = static_cast<int64_t>(start) - static_cast<int64_t>(operation.op.dev_offset);
operation.op.vmo_offset += diff;
operation.op.dev_offset = start;
operation.op.length = end - start;
}
storage::BufferedOperation operation;
};
// Traits which enable a BufferedOperation to exist in an interval tree.
struct RangeTraits {
static uint64_t Start(const RangeContainer& obj) { return obj.Start(); }
static uint64_t End(const RangeContainer& obj) { return obj.End(); }
static zx_status_t Update(const RangeContainer* other, uint64_t start, uint64_t end,
RangeContainer* obj);
};
using BufferedOperationRange = range::Range<uint64_t, RangeContainer, RangeTraits>;
using BufferedOperationTree = range::IntervalTree<BufferedOperationRange>;
} // namespace internal
// A tree which enables a caller to collect BufferedOperation objects used during journal replay. On
// insertion, the tree is updated to use the "latest" operation targetting a particular block.
class ReplayTree {
public:
using IterType = typename internal::BufferedOperationTree::IterType;
using ConstIterType = typename internal::BufferedOperationTree::ConstIterType;
ReplayTree();
// Inserts an operation into the replay tree.
//
// First, removes all overlapping prior operations which target the same device offset, and then
// inserts |operation|. This ensures that the "latest operation touching block B" will be the only
// operation from replay targetting that block.
void insert(storage::BufferedOperation operation);
void clear() { tree_.clear(); }
bool empty() const { return tree_.empty(); }
size_t size() const { return tree_.size(); }
IterType begin() { return tree_.begin(); }
ConstIterType begin() const { return tree_.begin(); }
IterType end() { return tree_.end(); }
ConstIterType end() const { return tree_.end(); }
private:
internal::BufferedOperationTree tree_;
};
} // namespace fs
#endif // SRC_STORAGE_LIB_VFS_CPP_JOURNAL_REPLAY_TREE_H_