aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Access/DiskAccessStorage.h
blob: 5d94008b34fad36419eb03e74c567f3e326f102c (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
90
91
92
93
94
95
#pragma once

#include <Access/MemoryAccessStorage.h>
#include <Common/ThreadPool_fwd.h>
#include <boost/container/flat_set.hpp>


namespace DB
{
class AccessChangesNotifier;

/// Loads and saves access entities on a local disk to a specified directory.
class DiskAccessStorage : public IAccessStorage
{
public:
    static constexpr char STORAGE_TYPE[] = "local_directory";

    DiskAccessStorage(const String & storage_name_, const String & directory_path_, AccessChangesNotifier & changes_notifier_, bool readonly_, bool allow_backup_);
    ~DiskAccessStorage() override;

    const char * getStorageType() const override { return STORAGE_TYPE; }
    String getStorageParamsJSON() const override;

    String getPath() const { return directory_path; }
    bool isPathEqual(const String & directory_path_) const;

    void setReadOnly(bool readonly_) { readonly = readonly_; }
    bool isReadOnly() const override { return readonly; }

    void reload(ReloadMode reload_mode) override;

    bool exists(const UUID & id) const override;

    bool isBackupAllowed() const override { return backup_allowed; }
    void restoreFromBackup(RestorerFromBackup & restorer) override;

private:
    std::optional<UUID> findImpl(AccessEntityType type, const String & name) const override;
    std::vector<UUID> findAllImpl(AccessEntityType type) const override;
    AccessEntityPtr readImpl(const UUID & id, bool throw_if_not_exists) const override;
    std::optional<std::pair<String, AccessEntityType>> readNameWithTypeImpl(const UUID & id, bool throw_if_not_exists) const override;
    bool insertImpl(const UUID & id, const AccessEntityPtr & entity, bool replace_if_exists, bool throw_if_exists) override;
    bool removeImpl(const UUID & id, bool throw_if_not_exists) override;
    bool updateImpl(const UUID & id, const UpdateFunc & update_func, bool throw_if_not_exists) override;

    bool readLists() TSA_REQUIRES(mutex);
    void writeLists() TSA_REQUIRES(mutex);
    void scheduleWriteLists(AccessEntityType type) TSA_REQUIRES(mutex);
    void reloadAllAndRebuildLists() TSA_REQUIRES(mutex);
    void setAllInMemory(const std::vector<std::pair<UUID, AccessEntityPtr>> & all_entities) TSA_REQUIRES(mutex);
    void removeAllExceptInMemory(const boost::container::flat_set<UUID> & ids_to_keep) TSA_REQUIRES(mutex);

    void listsWritingThreadFunc() TSA_NO_THREAD_SAFETY_ANALYSIS;
    void stopListsWritingThread();

    bool insertNoLock(const UUID & id, const AccessEntityPtr & new_entity, bool replace_if_exists, bool throw_if_exists, bool write_on_disk) TSA_REQUIRES(mutex);
    bool updateNoLock(const UUID & id, const UpdateFunc & update_func, bool throw_if_not_exists, bool write_on_disk) TSA_REQUIRES(mutex);
    bool removeNoLock(const UUID & id, bool throw_if_not_exists, bool write_on_disk) TSA_REQUIRES(mutex);

    AccessEntityPtr readAccessEntityFromDisk(const UUID & id) const;
    void writeAccessEntityToDisk(const UUID & id, const IAccessEntity & entity) const;
    void deleteAccessEntityOnDisk(const UUID & id) const;

    using NameToIDMap = std::unordered_map<String, UUID>;
    struct Entry
    {
        UUID id;
        String name;
        AccessEntityType type;
        mutable AccessEntityPtr entity; /// may be nullptr, if the entity hasn't been loaded yet.
    };

    String directory_path;

    std::unordered_map<UUID, Entry> entries_by_id TSA_GUARDED_BY(mutex);
    std::unordered_map<std::string_view, Entry *> entries_by_name_and_type[static_cast<size_t>(AccessEntityType::MAX)] TSA_GUARDED_BY(mutex);
    boost::container::flat_set<AccessEntityType> types_of_lists_to_write TSA_GUARDED_BY(mutex);

    /// Whether writing of the list files has been failed since the recent restart of the server.
    bool failed_to_write_lists TSA_GUARDED_BY(mutex) = false;

    /// List files are written in a separate thread.
    std::unique_ptr<ThreadFromGlobalPool> lists_writing_thread;

    /// Signals `lists_writing_thread` to exit.
    std::condition_variable lists_writing_thread_should_exit;

    bool lists_writing_thread_is_waiting = false;

    AccessChangesNotifier & changes_notifier;
    std::atomic<bool> readonly;
    std::atomic<bool> backup_allowed;
    mutable std::mutex mutex;
};
}