mirror of
https://github.com/scylladb/scylladb.git
synced 2026-04-26 19:35:12 +00:00
If there is a lot of partitions in the index page, index_list may grow large and require large contiguous blocks of memory. That puts pressure on the memory allocator, and if memory is fragmented, may not be possible to satisfy without a lot of eviction.
81 lines
2.9 KiB
C++
81 lines
2.9 KiB
C++
/*
|
|
* Copyright (C) 2017 ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* This file is part of Scylla.
|
|
*
|
|
* Scylla is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Scylla is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "index_entry.hh"
|
|
#include <vector>
|
|
#include <seastar/core/future.hh>
|
|
#include "utils/loading_shared_values.hh"
|
|
#include "utils/chunked_vector.hh"
|
|
|
|
namespace sstables {
|
|
|
|
using index_list = utils::chunked_vector<index_entry>;
|
|
|
|
// Associative cache of summary index -> index_list
|
|
// Entries stay around as long as there is any live external reference (list_ptr) to them.
|
|
// Supports asynchronous insertion, ensures that only one entry will be loaded.
|
|
class shared_index_lists {
|
|
public:
|
|
using key_type = uint64_t;
|
|
static thread_local struct stats {
|
|
uint64_t hits = 0; // Number of times entry was found ready
|
|
uint64_t misses = 0; // Number of times entry was not found
|
|
uint64_t blocks = 0; // Number of times entry was not ready (>= misses)
|
|
} _shard_stats;
|
|
|
|
struct stats_updater {
|
|
static void inc_hits() noexcept { ++_shard_stats.hits; }
|
|
static void inc_misses() noexcept { ++_shard_stats.misses; }
|
|
static void inc_blocks() noexcept { ++_shard_stats.blocks; }
|
|
static void inc_evictions() noexcept {}
|
|
};
|
|
|
|
using loading_shared_lists_type = utils::loading_shared_values<key_type, index_list, std::hash<key_type>, std::equal_to<key_type>, stats_updater>;
|
|
// Pointer to index_list
|
|
using list_ptr = loading_shared_lists_type::entry_ptr;
|
|
private:
|
|
|
|
loading_shared_lists_type _lists;
|
|
public:
|
|
|
|
shared_index_lists() = default;
|
|
shared_index_lists(shared_index_lists&&) = delete;
|
|
shared_index_lists(const shared_index_lists&) = delete;
|
|
|
|
// Returns a future which resolves with a shared pointer to index_list for given key.
|
|
// Always returns a valid pointer if succeeds. The pointer is never invalidated externally.
|
|
//
|
|
// If entry is missing, the loader is invoked. If list is already loading, this invocation
|
|
// will wait for prior loading to complete and use its result when it's done.
|
|
//
|
|
// The loader object does not survive deferring, so the caller must deal with its liveness.
|
|
template<typename Loader>
|
|
future<list_ptr> get_or_load(const key_type& key, Loader&& loader) {
|
|
return _lists.get_or_load(key, std::forward<Loader>(loader));
|
|
}
|
|
|
|
static const stats& shard_stats() { return _shard_stats; }
|
|
};
|
|
|
|
}
|