From d75289477f3c0c9cb89c2eb26a023329a7b50731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Wed, 8 Sep 2021 09:45:06 -0400 Subject: [PATCH] swarm: calculate linearizedParent while logging This makes the log sending messages in the order the client will show it and avoid to calculate linearized parent for each commit. However, this linearized parent can change over time. In fact, if a merge happens, the parents of the messages shown can be modified. Change-Id: I26372aa52de0e5f89140680a4beaf5fc7ec52163 GitLab: https://git.jami.net/savoirfairelinux/ring-project/-/issues/1282 --- src/jamidht/conversation.cpp | 3 +- src/jamidht/conversationrepository.cpp | 87 +++++-------------- src/jamidht/conversationrepository.h | 1 + test/unitTest/conversation/conversation.cpp | 9 +- .../conversationRepository.cpp | 1 + 5 files changed, 30 insertions(+), 71 deletions(-) diff --git a/src/jamidht/conversation.cpp b/src/jamidht/conversation.cpp index 62659d8f7f..995e638c9e 100644 --- a/src/jamidht/conversation.cpp +++ b/src/jamidht/conversation.cpp @@ -404,10 +404,9 @@ Conversation::Impl::convCommitToMap(const ConversationCommit& commit) const if (!extension.empty()) message["fileId"] += "." + extension; } - auto linearizedParent = repository_->linearizedParent(commit.id); message["id"] = commit.id; message["parents"] = parents; - message["linearizedParent"] = linearizedParent ? *linearizedParent : ""; + message["linearizedParent"] = commit.linearized_parent; message["author"] = authorId; message["type"] = type; message["timestamp"] = std::to_string(commit.timestamp); diff --git a/src/jamidht/conversationrepository.cpp b/src/jamidht/conversationrepository.cpp index d6235829c8..46282ab7ed 100644 --- a/src/jamidht/conversationrepository.cpp +++ b/src/jamidht/conversationrepository.cpp @@ -119,7 +119,6 @@ public: bool logIfNotFound = false, bool fastLog = false, const std::string& authorUri = "") const; - std::optional<std::string> linearizedParent(const std::string& commitId) const; GitObject fileAtTree(const std::string& path, const GitTree& tree) const; // NOTE! GitDiff needs to be deteleted before repo @@ -1533,20 +1532,21 @@ ConversationRepository::Impl::log(const std::string& from, const std::string& authorUri) const { std::vector<ConversationCommit> commits {}; + git_oid oid, oidFrom, oidMerge; - git_oid oid; + // Note: Start from head to get all merge possibilities and correct linearized parent. auto repo = repository(); - if (!repo) + if (!repo or git_reference_name_to_id(&oid, repo.get(), "HEAD") < 0) { + JAMI_ERR("Cannot get reference for HEAD"); return commits; - if (from.empty()) { - if (git_reference_name_to_id(&oid, repo.get(), "HEAD") < 0) { - JAMI_ERR("Cannot get reference for HEAD"); - return commits; - } - } else { - if (git_oid_fromstr(&oid, from.c_str()) < 0) { - JAMI_ERR("Cannot get reference for commit %s", from.c_str()); - return commits; + } + + if (from != "" && git_oid_fromstr(&oidFrom, from.c_str()) == 0) { + auto isMergeBase = git_merge_base(&oidMerge, repo.get(), &oid, &oidFrom) == 0 + && git_oid_equal(&oidMerge, &oidFrom); + if (!isMergeBase) { + // We're logging a non merged branch, so, take this one instead of HEAD + oid = oidFrom; } } @@ -1559,23 +1559,30 @@ ConversationRepository::Impl::log(const std::string& from, JAMI_DBG("Couldn't init revwalker for conversation %s", id_.c_str()); return commits; } + GitRevWalker walker {walker_ptr, git_revwalk_free}; git_revwalk_sorting(walker.get(), GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); + auto startLogging = from == ""; for (auto idx = 0u; !git_revwalk_next(&oid, walker.get()); ++idx) { - if (n != 0 && idx == n) { - break; - } git_commit* commit_ptr = nullptr; std::string id = git_oid_tostr_s(&oid); + if (!commits.empty()) { + // Set linearized parent + commits.rbegin()->linearized_parent = id; + } if (git_commit_lookup(&commit_ptr, repo.get(), &oid) < 0) { JAMI_WARN("Failed to look up commit %s", id.c_str()); break; } GitCommit commit {commit_ptr, git_commit_free}; - if (id == to) { + if ((n != 0 && commits.size() == n) || (id == to)) break; - } + + if (!startLogging && from != "" && from == id) + startLogging = true; + if (!startLogging) + continue; const git_signature* sig = git_commit_author(commit.get()); GitAuthor author; @@ -1625,49 +1632,9 @@ ConversationRepository::Impl::log(const std::string& from, git_buf_dispose(&signed_data); cc->timestamp = git_commit_time(commit.get()); } - return commits; } -std::optional<std::string> -ConversationRepository::Impl::linearizedParent(const std::string& commitId) const -{ - git_oid oid; - auto repo = repository(); - if (!repo or git_reference_name_to_id(&oid, repo.get(), "HEAD") < 0) { - JAMI_ERR("Cannot get reference for HEAD"); - return std::nullopt; - } - - git_revwalk* walker_ptr = nullptr; - if (git_revwalk_new(&walker_ptr, repo.get()) < 0 || git_revwalk_push(walker_ptr, &oid) < 0) { - GitRevWalker walker {walker_ptr, git_revwalk_free}; - // This fail can be ok in the case we check if a commit exists before pulling (so can fail - // there). only log if the fail is unwanted. - return std::nullopt; - } - GitRevWalker walker {walker_ptr, git_revwalk_free}; - git_revwalk_sorting(walker.get(), GIT_SORT_TOPOLOGICAL | GIT_SORT_TIME); - - auto ret = false; - for (auto idx = 0u; !git_revwalk_next(&oid, walker.get()); ++idx) { - git_commit* commit_ptr = nullptr; - std::string id = git_oid_tostr_s(&oid); - if (git_commit_lookup(&commit_ptr, repo.get(), &oid) < 0) { - JAMI_WARN("Failed to look up commit %s", id.c_str()); - break; - } - GitCommit commit {commit_ptr, git_commit_free}; - - if (ret) - return id; - if (id == commitId) - ret = true; - } - - return std::nullopt; -} - GitObject ConversationRepository::Impl::fileAtTree(const std::string& path, const GitTree& tree) const { @@ -2927,12 +2894,6 @@ ConversationRepository::validClone() const return pimpl_->validCommits(logN("", 0)); } -std::optional<std::string> -ConversationRepository::linearizedParent(const std::string& commitId) const -{ - return pimpl_->linearizedParent(commitId); -} - void ConversationRepository::removeBranchWith(const std::string& remoteDevice) { diff --git a/src/jamidht/conversationrepository.h b/src/jamidht/conversationrepository.h index b4a73a230c..ed26caa82a 100644 --- a/src/jamidht/conversationrepository.h +++ b/src/jamidht/conversationrepository.h @@ -69,6 +69,7 @@ struct ConversationCommit std::vector<uint8_t> signed_content {}; std::vector<uint8_t> signature {}; std::string commit_msg {}; + std::string linearized_parent {}; int64_t timestamp {0}; }; diff --git a/test/unitTest/conversation/conversation.cpp b/test/unitTest/conversation/conversation.cpp index a6214b6328..b407317e6e 100644 --- a/test/unitTest/conversation/conversation.cpp +++ b/test/unitTest/conversation/conversation.cpp @@ -1064,14 +1064,11 @@ ConversationTest::testPingPongMessages() [&](const std::string& accountId, const std::string& /* conversationId */, std::map<std::string, std::string> /*message*/) { - if (accountId == bobId) { + if (accountId == bobId) messageBobReceived += 1; - } - if (accountId == aliceId) { + if (accountId == aliceId) messageAliceReceived += 1; - } - if (messageAliceReceived == messageBobReceived) - cv.notify_one(); + cv.notify_one(); })); confHandlers.insert( DRing::exportable_callback<DRing::ConversationSignal::ConversationRequestReceived>( diff --git a/test/unitTest/conversationRepository/conversationRepository.cpp b/test/unitTest/conversationRepository/conversationRepository.cpp index 2d8fb93c29..b688cbe0c1 100644 --- a/test/unitTest/conversationRepository/conversationRepository.cpp +++ b/test/unitTest/conversationRepository/conversationRepository.cpp @@ -426,6 +426,7 @@ ConversationRepositoryTest::testFetch() // Clone repository auto id1 = repository->commitMessage("Commit 1"); + auto cloned = ConversationRepository::cloneConversation(bobAccount->weak(), aliceDeviceId.toString(), repository->id()); -- GitLab