/* * Copyright (C) 2017-present ScyllaDB * */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include "sstables/key.hh" #include "dht/i_partitioner.hh" namespace sstables { /** * @returns: >= 0, if key is found. That is the index where the key is found. * -1, if key is not found, and is smaller than the first key in the list. * <= -2, if key is not found, but is greater than one of the keys. By adding 2 and * negating, one can determine the index before which the key would have to * be inserted. * * Origin uses this slightly modified binary search for the Summary, that will * indicate in which bucket the element would be in case it is not a match. * * For the Index entries, it uses a "normal", java.lang binary search. Because * we have made the explicit decision to open code the comparator for * efficiency, using a separate binary search would be possible, but very * messy. * * It's easier to reuse the same code for both binary searches, and just ignore * the extra information when not needed. * * This code should work in all kinds of vectors in whose's elements is possible to acquire * a key view via get_key(). */ template int binary_search(const dht::i_partitioner& partitioner, const T& entries, const key& sk, const dht::token& token) { int low = 0, mid = entries.size(), high = mid - 1; std::strong_ordering result = std::strong_ordering::less; while (low <= high) { // The token comparison should yield the right result most of the time. // So we avoid expensive copying operations that happens at key // creation by keeping only a key view, and then manually carrying out // both parts of the comparison ourselves. mid = low + ((high - low) >> 1); key_view mid_key = entries[mid].get_key(); auto mid_token = partitioner.get_token(mid_key); if (token == mid_token) { result = sk.tri_compare(mid_key); } else { result = token < mid_token ? std::strong_ordering::less : std::strong_ordering::greater; } if (result > 0) { low = mid + 1; } else if (result < 0) { high = mid - 1; } else { return mid; } } return -mid - (result < 0 ? 1 : 2); } template int binary_search(const dht::i_partitioner& partitioner, const T& entries, const key& sk) { return binary_search(partitioner, entries, sk, partitioner.get_token(key_view(sk))); } }