Skip to content

Commit

Permalink
configuration_manager: using binary search to replace linear search. (#9
Browse files Browse the repository at this point in the history
)

entries index of `configuration manager` is strictly increase
monotonically, we can use binary search to replace linear search.

details: #9
  • Loading branch information
ehds authored Apr 28, 2024
1 parent e9d26a8 commit 9a20605
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 25 deletions.
52 changes: 33 additions & 19 deletions src/braft/configuration_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "braft/configuration_manager.h"

#include <algorithm>

namespace braft {

int ConfigurationManager::add(ConfigurationEntry&& entry) {
Expand All @@ -31,17 +33,27 @@ int ConfigurationManager::add(ConfigurationEntry&& entry) {
}

void ConfigurationManager::truncate_prefix(const int64_t first_index_kept) {
while (!_configurations.empty() &&
_configurations.front().id.index < first_index_kept) {
_configurations.pop_front();
}
// Find the first element which index >= `first_index_kept`.
auto it = std::lower_bound(
_configurations.begin(), _configurations.end(), first_index_kept,
[](const ConfigurationEntry& entry, int64_t index) {
return entry.id.index < index;
});

// Remove prefix [begin, index).
_configurations.erase(_configurations.begin(), it);
}

void ConfigurationManager::truncate_suffix(const int64_t last_index_kept) {
while (!_configurations.empty() &&
_configurations.back().id.index > last_index_kept) {
_configurations.pop_back();
}
// Find the first element which index > `last_index_kept`.
auto it = std::upper_bound(
_configurations.begin(), _configurations.end(), last_index_kept,
[](int64_t index, const ConfigurationEntry& entry) {
return index < entry.id.index;
});

// Remove suffix [index, end].
_configurations.erase(it, _configurations.end());
}

void ConfigurationManager::set_snapshot(ConfigurationEntry&& entry) {
Expand All @@ -56,17 +68,19 @@ void ConfigurationManager::get(int64_t last_included_index,
*conf = _snapshot;
return;
}
std::deque<ConfigurationEntry>::iterator it;
for (it = _configurations.begin(); it != _configurations.end(); ++it) {
if (it->id.index > last_included_index) {
break;
}
}
if (it == _configurations.begin()) {
*conf = _snapshot;
return;
}
--it;

// Entries index is strictly increase monotonically.
// We can use binary search to find the i which
// _configurations[i-1].index < `last_included_index` <=
// _configurations[i].id.index
// From end to begin, the first element which index <= `last_included_index`
auto it = std::lower_bound(
_configurations.rbegin(), _configurations.rend(), last_included_index,
[](const ConfigurationEntry& rhs, int64_t index) {
return rhs.id.index > index;
});

CHECK(it != _configurations.rend());
*conf = *it;
}

Expand Down
45 changes: 39 additions & 6 deletions test/test_configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,20 +114,24 @@ TEST_F(TestUsageSuits, Configuration) {
std::set<PeerId> peer_set3;
conf2.list_peers(&peer_set3);
ASSERT_EQ(peer_set.size(), 3);

// invalid format.
Configuration conf4;
ASSERT_EQ(conf4.parse_from("1.1,1.1:100,1.1.1:100:3,aaabbbccc"), -1);
}

TEST_F(TestUsageSuits, ConfigurationManager) {
ConfigurationManager conf_manager;

ConfigurationEntry it1;
conf_manager.get(10, &it1);
ASSERT_EQ(it1.id, LogId(0, 0));
ASSERT_TRUE(it1.conf.empty());

// Truncate empty config manager.
conf_manager.truncate_prefix(42);
conf_manager.truncate_suffix(42);
ASSERT_EQ(LogId(0, 0), conf_manager.last_configuration().id);

ConfigurationEntry entry;
std::vector<PeerId> peers;
peers.emplace_back("1.1.1.1:1000:0");
Expand All @@ -138,26 +142,55 @@ TEST_F(TestUsageSuits, ConfigurationManager) {
conf_manager.add(ConfigurationEntry{entry});

ASSERT_EQ(LogId(8, 1), conf_manager.last_configuration().id);

conf_manager.get(8, &it1);
ASSERT_EQ(it1.id, entry.id);
conf_manager.get(10, &it1);
ASSERT_EQ(it1.id, entry.id);

// truncate suffix (8, end).
conf_manager.truncate_suffix(8);
// 8 must exists.
ASSERT_EQ(LogId(8, 1), conf_manager.last_configuration().id);

// truncate prefix [1, 8).
conf_manager.truncate_prefix(8);
// 8 must exists.
ASSERT_EQ(LogId(8, 1), conf_manager.last_configuration().id);

// truncate suffix (7, end).
conf_manager.truncate_suffix(7);
// 8 not fount.
ASSERT_EQ(LogId(0, 0), conf_manager.last_configuration().id);

// Add [10, 15, 20] entries.
entry.id = LogId(10, 1);
entry.conf = peers;
conf_manager.add(ConfigurationEntry{entry});
peers.emplace_back("1.1.1.1:1000:3");
entry.id = LogId(15, 1);
entry.conf = peers;
conf_manager.add(ConfigurationEntry{entry});
entry.id = LogId(20, 1);
entry.conf = peers;
conf_manager.add(ConfigurationEntry{entry});
ASSERT_EQ(LogId(20, 1), conf_manager.last_configuration().id);

conf_manager.truncate_prefix(15);
ASSERT_EQ(LogId(20, 1), conf_manager.last_configuration().id);
ConfigurationEntry ce;
conf_manager.get(16, &ce);
ASSERT_EQ(LogId(15, 1), ce.id);
// conf_manager.get(8, &ce); // FATAL.
// ASSERT_EQ(LogId(0, 0), ce.id);

conf_manager.truncate_prefix(25);
conf_manager.truncate_prefix(10);
conf_manager.get(10, &ce);
ASSERT_EQ(LogId(10, 1), ce.id);

ASSERT_EQ(LogId(20, 1), conf_manager.last_configuration().id);
conf_manager.truncate_prefix(16);
ASSERT_EQ(LogId(20, 1), conf_manager.last_configuration().id);
conf_manager.truncate_suffix(20);
ASSERT_EQ(LogId(20, 1), conf_manager.last_configuration().id);
conf_manager.truncate_suffix(19);
ASSERT_EQ(LogId(0, 0), conf_manager.last_configuration().id);
}
} // namespace test
Expand Down

0 comments on commit 9a20605

Please sign in to comment.