aboutsummaryrefslogtreecommitdiffstats
path: root/storage/src/vespa/storage/bucketdb/striped_btree_lockable_map.h
blob: 8b6b7e43ef9ce1d6b671a7a7702d04278abd3006 (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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once

#include "btree_lockable_map.h"
#include <memory>
#include <vector>

namespace storage::bucketdb {

/**
 * Bucket database implementation that stripes all superbuckets across
 * a set of disjoint sub-DBs. All locking is handled by the individual
 * sub-DBs, meaning that accessing one does not cause contention for
 * readers/writers accessing another.
 * Ordered iteration is transparently provided by the const for_each method
 * and by read guards.
 */
template <typename T>
class StripedBTreeLockableMap final : public AbstractBucketMap<T> {
public:
    using ParentType   = AbstractBucketMap<T>;
    using WrappedEntry = typename ParentType::WrappedEntry;
    using key_type     = typename ParentType::key_type;
    using mapped_type  = typename ParentType::mapped_type;
    using LockId       = typename ParentType::LockId;
    using EntryMap     = typename ParentType::EntryMap;
    using Decision     = typename ParentType::Decision;
    using BucketId     = document::BucketId;

private:
    using StripedDBType = BTreeLockableMap<T>;
    uint8_t _n_stripe_bits;
    size_t _n_stripes;
    std::vector<std::unique_ptr<StripedDBType>> _stripes;
public:
    explicit StripedBTreeLockableMap(uint8_t n_stripe_bits = 4);
    ~StripedBTreeLockableMap() override;

    size_t size() const noexcept override;
    size_t getMemoryUsage() const noexcept override;
    vespalib::MemoryUsage detailed_memory_usage() const noexcept override;
    bool empty() const noexcept override;

    WrappedEntry get(const key_type& key, const char* clientId, bool createIfNonExisting) override;
    WrappedEntry get(const key_type& key, const char* clientId) {
        return get(key, clientId, false);
    }
    bool erase(const key_type& key, const char* clientId, bool has_lock) override;
    void insert(const key_type& key, const mapped_type& value,
                const char* client_id, bool has_lock, bool& pre_existed) override;

    bool erase(const key_type& key, const char* client_id) {
        return erase(key, client_id, false);
    }
    void insert(const key_type& key, const mapped_type& value,
                const char* client_id, bool& pre_existed) {
        return insert(key, value, client_id, false, pre_existed);
    }
    void clear();
    void print(std::ostream& out, bool verbose, const std::string& indent) const override;
    EntryMap getContained(const BucketId& bucketId, const char* clientId) override;
    EntryMap getAll(const BucketId& bucketId, const char* clientId) override;
    bool isConsistent(const WrappedEntry& entry) const override;
    void showLockClients(vespalib::asciistream & out) const override;

private:
    class ReadGuardImpl;

    void unlock(const key_type& key) override;

    void do_for_each_mutable_unordered(std::function<Decision(uint64_t, mapped_type&)> func,
                                       const char* client_id) override;

    void do_for_each(std::function<Decision(uint64_t, const mapped_type&)> func,
                     const char* client_id) override;

    void do_for_each_chunked(std::function<Decision(uint64_t, const mapped_type&)> func,
                             const char* client_id,
                             vespalib::duration yield_time,
                             uint32_t chunk_size) override;

    std::unique_ptr<ReadGuard<T>> do_acquire_read_guard() const override;

    [[nodiscard]] size_t stripe_of(key_type) const noexcept;
    [[nodiscard]] StripedDBType& db_for(key_type) noexcept;
    [[nodiscard]] const StripedDBType& db_for(key_type) const noexcept;
};

}