Currently, there are 2 ways of sharing a backlog with other nodes: through a gossip mechanism, and with responses to replica writes. In gossip, we check each second if the backlog changed, and if it did we update other nodes with it. However if the backlog for this node changed on another node with a write response, the gossiped backlog is currently not updated, so if after the response the backlog goes back to the value from the previous gossip round, it will not get sent and the other node will stay with an outdated backlog. This patch changes this by notifying the gossip that a the backlog changed since the last gossip round so a different backlog could have been send through the response piggyback mechanism. With that information, gossip will send an unchanged backlog to other nodes in the following gossip round. Fixes: https://github.com/scylladb/scylladb/issues/18461
65 lines
1.8 KiB
C++
65 lines
1.8 KiB
C++
/*
|
|
* Copyright (C) 2018-present ScyllaDB
|
|
*/
|
|
|
|
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "db/view/view_update_backlog.hh"
|
|
|
|
#include <seastar/core/cacheline.hh>
|
|
#include <seastar/core/future.hh>
|
|
#include <seastar/core/lowres_clock.hh>
|
|
#include <seastar/util/bool_class.hh>
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <new>
|
|
|
|
namespace db::view {
|
|
|
|
/**
|
|
* An atomic view update backlog representation, safe to update from multiple shards.
|
|
* It is legal for a stale current max value to be returned.
|
|
*/
|
|
class node_update_backlog {
|
|
using clock = seastar::lowres_clock;
|
|
using need_publishing = seastar::bool_class<class need_publishing_tag>;
|
|
struct per_shard_backlog {
|
|
// Multiply by 2 to defeat the prefetcher
|
|
alignas(seastar::cache_line_size * 2) std::atomic<update_backlog> backlog = update_backlog::no_backlog();
|
|
need_publishing need_publishing = need_publishing::no;
|
|
|
|
update_backlog load() const {
|
|
return backlog.load(std::memory_order_relaxed);
|
|
}
|
|
};
|
|
std::vector<per_shard_backlog> _backlogs;
|
|
std::chrono::milliseconds _interval;
|
|
std::atomic<clock::time_point> _last_update;
|
|
std::atomic<update_backlog> _max;
|
|
|
|
public:
|
|
explicit node_update_backlog(size_t shards, std::chrono::milliseconds interval)
|
|
: _backlogs(shards)
|
|
, _interval(interval)
|
|
, _last_update(clock::now() - _interval)
|
|
, _max(update_backlog::no_backlog()) {
|
|
}
|
|
|
|
update_backlog fetch();
|
|
void add(update_backlog backlog);
|
|
update_backlog fetch_shard(unsigned shard);
|
|
seastar::future<std::optional<update_backlog>> fetch_if_changed();
|
|
|
|
// Exposed for testing only.
|
|
update_backlog load() const {
|
|
return _max.load(std::memory_order_relaxed);
|
|
}
|
|
};
|
|
|
|
}
|