aboutsummaryrefslogtreecommitdiffstats
path: root/storage/src/vespa/storage/distributor/operations/cancel_scope.h
blob: 7619a64d39f6f9aaa333ab5532e013bc738809f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include <vespa/vespalib/stllike/hash_set.h>

namespace storage::distributor {

/**
 * In the face of concurrent cluster state changes, cluster topology reconfigurations etc.,
 * it's possible for there to be pending mutating operations to nodes that the distributor
 * no longer should keep track of. Such operations must therefore be _cancelled_, either
 * fully or partially. A CancelScope represents the granularity at which an operation should
 * be cancelled.
 *
 * In the case of one or more nodes becoming unavailable, `fully_cancelled()` will be false
 * and `node_is_cancelled(x)` will return whether node `x` is explicitly cancelled.
 *
 * In the case of ownership transfers, `fully_cancelled()` will be true since the distributor
 * should no longer have any knowledge of the bucket. `node_is_cancelled(x)` is always
 * implicitly true for all values of `x` for full cancellations.
 */
class CancelScope {
public:
    using CancelledNodeSet = vespalib::hash_set<uint16_t>;
private:
    CancelledNodeSet _cancelled_nodes;
    bool             _fully_cancelled;

    struct fully_cancelled_ctor_tag {};

    explicit CancelScope(fully_cancelled_ctor_tag) noexcept;
    explicit CancelScope(CancelledNodeSet nodes) noexcept;
public:
    CancelScope();
    ~CancelScope();

    CancelScope(const CancelScope&);
    CancelScope& operator=(const CancelScope&);

    CancelScope(CancelScope&&) noexcept;
    CancelScope& operator=(CancelScope&&) noexcept;

    void add_cancelled_node(uint16_t node);
    void merge(const CancelScope& other);

    [[nodiscard]] bool fully_cancelled() const noexcept { return _fully_cancelled; }
    [[nodiscard]] bool is_cancelled() const noexcept {
        return (_fully_cancelled || !_cancelled_nodes.empty());
    }
    [[nodiscard]] bool node_is_cancelled(uint16_t node) const noexcept {
        return (fully_cancelled() || _cancelled_nodes.contains(node));
    }

    [[nodiscard]] const CancelledNodeSet& cancelled_nodes() const noexcept {
        return _cancelled_nodes;
    }

    static CancelScope of_fully_cancelled() noexcept;
    static CancelScope of_node_subset(CancelledNodeSet nodes) noexcept;
};

}