1 | #include <Access/MultipleAccessStorage.h> |
2 | #include <Common/Exception.h> |
3 | #include <Common/quoteString.h> |
4 | |
5 | |
6 | namespace DB |
7 | { |
8 | namespace ErrorCodes |
9 | { |
10 | extern const int ACCESS_ENTITY_NOT_FOUND; |
11 | extern const int ACCESS_ENTITY_FOUND_DUPLICATES; |
12 | } |
13 | |
14 | |
15 | namespace |
16 | { |
17 | template <typename StoragePtrT> |
18 | String joinStorageNames(const std::vector<StoragePtrT> & storages) |
19 | { |
20 | String result; |
21 | for (const auto & storage : storages) |
22 | { |
23 | if (!result.empty()) |
24 | result += ", " ; |
25 | result += storage->getStorageName(); |
26 | } |
27 | return result; |
28 | } |
29 | } |
30 | |
31 | |
32 | MultipleAccessStorage::MultipleAccessStorage( |
33 | std::vector<std::unique_ptr<Storage>> nested_storages_, size_t index_of_nested_storage_for_insertion_) |
34 | : IAccessStorage(joinStorageNames(nested_storages_)) |
35 | , nested_storages(std::move(nested_storages_)) |
36 | , nested_storage_for_insertion(nested_storages[index_of_nested_storage_for_insertion_].get()) |
37 | , ids_cache(512 /* cache size */) |
38 | { |
39 | } |
40 | |
41 | |
42 | MultipleAccessStorage::~MultipleAccessStorage() |
43 | { |
44 | } |
45 | |
46 | |
47 | std::vector<UUID> MultipleAccessStorage::findMultiple(std::type_index type, const String & name) const |
48 | { |
49 | std::vector<UUID> ids; |
50 | for (const auto & nested_storage : nested_storages) |
51 | { |
52 | auto id = nested_storage->find(type, name); |
53 | if (id) |
54 | { |
55 | std::lock_guard lock{ids_cache_mutex}; |
56 | ids_cache.set(*id, std::make_shared<Storage *>(nested_storage.get())); |
57 | ids.push_back(*id); |
58 | } |
59 | } |
60 | return ids; |
61 | } |
62 | |
63 | |
64 | std::optional<UUID> MultipleAccessStorage::findImpl(std::type_index type, const String & name) const |
65 | { |
66 | auto ids = findMultiple(type, name); |
67 | if (ids.empty()) |
68 | return {}; |
69 | if (ids.size() == 1) |
70 | return ids[0]; |
71 | |
72 | std::vector<const Storage *> storages_with_duplicates; |
73 | for (const auto & id : ids) |
74 | { |
75 | auto * storage = findStorage(id); |
76 | if (storage) |
77 | storages_with_duplicates.push_back(storage); |
78 | } |
79 | |
80 | throw Exception( |
81 | "Found " + getTypeName(type) + " " + backQuote(name) + " in " + std::to_string(ids.size()) |
82 | + " storages: " + joinStorageNames(storages_with_duplicates), |
83 | ErrorCodes::ACCESS_ENTITY_FOUND_DUPLICATES); |
84 | } |
85 | |
86 | |
87 | std::vector<UUID> MultipleAccessStorage::findAllImpl(std::type_index type) const |
88 | { |
89 | std::vector<UUID> all_ids; |
90 | for (const auto & nested_storage : nested_storages) |
91 | { |
92 | auto ids = nested_storage->findAll(type); |
93 | all_ids.insert(all_ids.end(), std::make_move_iterator(ids.begin()), std::make_move_iterator(ids.end())); |
94 | } |
95 | return all_ids; |
96 | } |
97 | |
98 | |
99 | bool MultipleAccessStorage::existsImpl(const UUID & id) const |
100 | { |
101 | return findStorage(id) != nullptr; |
102 | } |
103 | |
104 | |
105 | IAccessStorage * MultipleAccessStorage::findStorage(const UUID & id) |
106 | { |
107 | { |
108 | std::lock_guard lock{ids_cache_mutex}; |
109 | auto from_cache = ids_cache.get(id); |
110 | if (from_cache) |
111 | { |
112 | auto * storage = *from_cache; |
113 | if (storage->exists(id)) |
114 | return storage; |
115 | } |
116 | } |
117 | |
118 | for (const auto & nested_storage : nested_storages) |
119 | { |
120 | if (nested_storage->exists(id)) |
121 | { |
122 | std::lock_guard lock{ids_cache_mutex}; |
123 | ids_cache.set(id, std::make_shared<Storage *>(nested_storage.get())); |
124 | return nested_storage.get(); |
125 | } |
126 | } |
127 | |
128 | return nullptr; |
129 | } |
130 | |
131 | |
132 | const IAccessStorage * MultipleAccessStorage::findStorage(const UUID & id) const |
133 | { |
134 | return const_cast<MultipleAccessStorage *>(this)->findStorage(id); |
135 | } |
136 | |
137 | |
138 | IAccessStorage & MultipleAccessStorage::getStorage(const UUID & id) |
139 | { |
140 | auto * storage = findStorage(id); |
141 | if (storage) |
142 | return *storage; |
143 | throwNotFound(id); |
144 | } |
145 | |
146 | |
147 | const IAccessStorage & MultipleAccessStorage::getStorage(const UUID & id) const |
148 | { |
149 | return const_cast<MultipleAccessStorage *>(this)->getStorage(id); |
150 | } |
151 | |
152 | |
153 | AccessEntityPtr MultipleAccessStorage::readImpl(const UUID & id) const |
154 | { |
155 | return getStorage(id).read(id); |
156 | } |
157 | |
158 | |
159 | String MultipleAccessStorage::readNameImpl(const UUID & id) const |
160 | { |
161 | return getStorage(id).readName(id); |
162 | } |
163 | |
164 | |
165 | UUID MultipleAccessStorage::insertImpl(const AccessEntityPtr & entity, bool replace_if_exists) |
166 | { |
167 | auto id = replace_if_exists ? nested_storage_for_insertion->insertOrReplace(entity) : nested_storage_for_insertion->insert(entity); |
168 | |
169 | std::lock_guard lock{ids_cache_mutex}; |
170 | ids_cache.set(id, std::make_shared<Storage *>(nested_storage_for_insertion)); |
171 | |
172 | return id; |
173 | } |
174 | |
175 | |
176 | void MultipleAccessStorage::removeImpl(const UUID & id) |
177 | { |
178 | getStorage(id).remove(id); |
179 | } |
180 | |
181 | |
182 | void MultipleAccessStorage::updateImpl(const UUID & id, const UpdateFunc & update_func) |
183 | { |
184 | getStorage(id).update(id, update_func); |
185 | } |
186 | |
187 | |
188 | IAccessStorage::SubscriptionPtr MultipleAccessStorage::subscribeForChangesImpl(const UUID & id, const OnChangedHandler & handler) const |
189 | { |
190 | auto storage = findStorage(id); |
191 | if (!storage) |
192 | return nullptr; |
193 | return storage->subscribeForChanges(id, handler); |
194 | } |
195 | |
196 | |
197 | IAccessStorage::SubscriptionPtr MultipleAccessStorage::subscribeForChangesImpl(std::type_index type, const OnChangedHandler & handler) const |
198 | { |
199 | std::vector<SubscriptionPtr> subscriptions; |
200 | for (const auto & nested_storage : nested_storages) |
201 | { |
202 | auto subscription = nested_storage->subscribeForChanges(type, handler); |
203 | if (subscription) |
204 | subscriptions.emplace_back(std::move(subscription)); |
205 | } |
206 | |
207 | if (subscriptions.empty()) |
208 | return nullptr; |
209 | |
210 | if (subscriptions.size() == 1) |
211 | return std::move(subscriptions[0]); |
212 | |
213 | class SubscriptionImpl : public Subscription |
214 | { |
215 | public: |
216 | SubscriptionImpl(std::vector<SubscriptionPtr> subscriptions_) |
217 | : subscriptions(std::move(subscriptions_)) {} |
218 | private: |
219 | std::vector<SubscriptionPtr> subscriptions; |
220 | }; |
221 | |
222 | return std::make_unique<SubscriptionImpl>(std::move(subscriptions)); |
223 | } |
224 | |
225 | |
226 | bool MultipleAccessStorage::hasSubscriptionImpl(const UUID & id) const |
227 | { |
228 | for (const auto & nested_storage : nested_storages) |
229 | { |
230 | if (nested_storage->hasSubscription(id)) |
231 | return true; |
232 | } |
233 | return false; |
234 | } |
235 | |
236 | |
237 | bool MultipleAccessStorage::hasSubscriptionImpl(std::type_index type) const |
238 | { |
239 | for (const auto & nested_storage : nested_storages) |
240 | { |
241 | if (nested_storage->hasSubscription(type)) |
242 | return true; |
243 | } |
244 | return false; |
245 | } |
246 | } |
247 | |