blob: 19f62537b867ae9d3e03781f193bdfc2ae6052d8 [file] [log] [blame]
// Copyright 2017 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.
#include <lib/callback/operation_serializer.h>
#include <lib/callback/waiter.h>
#include <lib/fit/function.h>
#include <memory>
#include <vector>
#include "src/ledger/bin/app/diff_utils.h"
#include "src/ledger/bin/app/page_manager.h"
#include "src/ledger/bin/fidl/error_notifier.h"
#include "src/ledger/bin/fidl/include/types.h"
#include "src/ledger/bin/storage/public/commit.h"
#include "src/ledger/bin/storage/public/page_storage.h"
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/memory/weak_ptr.h"
namespace ledger {
// Client handling communication with a ConflictResolver interface in order to
// merge conflicting commit branches. It is used both by AutoMergeStrategy and
// CustomMergeStrategy.
class ConflictResolverClient
: public fuchsia::ledger::MergeResultProviderErrorNotifierDelegate {
explicit ConflictResolverClient(
storage::PageStorage* storage, PageManager* page_manager,
ConflictResolver* conflict_resolver,
std::unique_ptr<const storage::Commit> left,
std::unique_ptr<const storage::Commit> right,
std::unique_ptr<const storage::Commit> ancestor,
fit::function<void(storage::Status)> callback);
~ConflictResolverClient() override;
void Start();
void Cancel();
// Gets or creates the object identifier associated to the given
// |merge_value|. This method can only be called on merge values whose source
// is either |NEW| or |RIGHT|.
void GetOrCreateObjectIdentifier(
const MergedValue& merged_value,
fit::function<void(storage::Status, storage::ObjectIdentifier)> callback);
// Rolls back journal, closes merge result provider and invokes callback_ with
// |status|. This method must be called at most once.
void Finalize(storage::Status status);
// Performs a diff of the given type on the conflict. Return a
// |storage::Status| different than OK if an error occured. If no error,
// return an |IterationStatus|.
void GetDiff(
diff_utils::DiffType type, std::unique_ptr<Token> token,
fit::function<void(storage::Status, IterationStatus,
std::vector<DiffEntry>, std::unique_ptr<Token>)>
// MergeResultProviderNotifierDelegate:
void GetFullDiff(
std::unique_ptr<Token> token,
fit::function<void(Status, IterationStatus, std::vector<DiffEntry>,
callback) override;
void GetConflictingDiff(
std::unique_ptr<Token> token,
fit::function<void(Status, IterationStatus, std::vector<DiffEntry>,
callback) override;
void Merge(std::vector<MergedValue> merged_values,
fit::function<void(Status)> callback) override;
void MergeNonConflictingEntries(
fit::function<void(Status)> callback) override;
void Done(fit::function<void(Status)> callback) override;
// Checks whether this ConflictResolverClient is still valid (not deleted nor
// cancelled) and the status is OK. Returns |true| in that case. Otherwise,
// calls |callback| with the given |status| and calls |Finalize| if this
// object is not deleted, then return |false|.
static bool IsInValidStateAndNotify(
const fxl::WeakPtr<ConflictResolverClient>& weak_this,
const fit::function<void(storage::Status)>& callback,
storage::Status status = storage::Status::OK);
storage::PageStorage* const storage_;
PageManager* const manager_;
ConflictResolver* const conflict_resolver_;
std::unique_ptr<const storage::Commit> const left_;
std::unique_ptr<const storage::Commit> const right_;
std::unique_ptr<const storage::Commit> const ancestor_;
// Called when the merge process is finished.
fit::function<void(storage::Status)> callback_;
// |has_merged_values_| is true when |Merge| has been called to set some
// values. It is used as an optimization in |MergeNonConflictingEntries|.
bool has_merged_values_ = false;
std::unique_ptr<storage::Journal> journal_;
// |in_client_request_| is true when waiting for the callback of the
// ConflictResolver.Resolve call. When this merge is cancelled, we check this
// boolean to know if we should abort immediately (when in a client request,
// as the client may have disconnected) and when we should wait for the
// operation to finish (the other cases, such as committing the merge).
bool in_client_request_ = false;
bool cancelled_ = false;
// Operations are operating on the state of the merge commit. They must be
// serialized.
callback::OperationSerializer operation_serializer_;
// This must be the last member of the class.
fxl::WeakPtrFactory<ConflictResolverClient> weak_factory_;
} // namespace ledger