1 | #include <Access/IAccessStorage.h> |
2 | #include <Common/Exception.h> |
3 | #include <Common/quoteString.h> |
4 | #include <IO/WriteHelpers.h> |
5 | #include <Poco/UUIDGenerator.h> |
6 | #include <Poco/Logger.h> |
7 | |
8 | |
9 | namespace DB |
10 | { |
11 | namespace ErrorCodes |
12 | { |
13 | extern const int BAD_CAST; |
14 | extern const int ACCESS_ENTITY_NOT_FOUND; |
15 | extern const int ACCESS_ENTITY_ALREADY_EXISTS; |
16 | extern const int ACCESS_ENTITY_FOUND_DUPLICATES; |
17 | extern const int ACCESS_ENTITY_STORAGE_READONLY; |
18 | } |
19 | |
20 | |
21 | std::vector<UUID> IAccessStorage::findAll(std::type_index type) const |
22 | { |
23 | return findAllImpl(type); |
24 | } |
25 | |
26 | |
27 | std::optional<UUID> IAccessStorage::find(std::type_index type, const String & name) const |
28 | { |
29 | return findImpl(type, name); |
30 | } |
31 | |
32 | |
33 | std::vector<UUID> IAccessStorage::find(std::type_index type, const Strings & names) const |
34 | { |
35 | std::vector<UUID> ids; |
36 | ids.reserve(names.size()); |
37 | for (const String & name : names) |
38 | { |
39 | auto id = findImpl(type, name); |
40 | if (id) |
41 | ids.push_back(*id); |
42 | } |
43 | return ids; |
44 | } |
45 | |
46 | |
47 | UUID IAccessStorage::getID(std::type_index type, const String & name) const |
48 | { |
49 | auto id = findImpl(type, name); |
50 | if (id) |
51 | return *id; |
52 | throwNotFound(type, name); |
53 | } |
54 | |
55 | |
56 | std::vector<UUID> IAccessStorage::getIDs(std::type_index type, const Strings & names) const |
57 | { |
58 | std::vector<UUID> ids; |
59 | ids.reserve(names.size()); |
60 | for (const String & name : names) |
61 | ids.push_back(getID(type, name)); |
62 | return ids; |
63 | } |
64 | |
65 | |
66 | bool IAccessStorage::exists(const UUID & id) const |
67 | { |
68 | return existsImpl(id); |
69 | } |
70 | |
71 | |
72 | |
73 | AccessEntityPtr IAccessStorage::tryReadBase(const UUID & id) const |
74 | { |
75 | try |
76 | { |
77 | return readImpl(id); |
78 | } |
79 | catch (Exception &) |
80 | { |
81 | return nullptr; |
82 | } |
83 | } |
84 | |
85 | |
86 | String IAccessStorage::readName(const UUID & id) const |
87 | { |
88 | return readNameImpl(id); |
89 | } |
90 | |
91 | |
92 | std::optional<String> IAccessStorage::tryReadName(const UUID & id) const |
93 | { |
94 | try |
95 | { |
96 | return readNameImpl(id); |
97 | } |
98 | catch (Exception &) |
99 | { |
100 | return {}; |
101 | } |
102 | } |
103 | |
104 | |
105 | UUID IAccessStorage::insert(const AccessEntityPtr & entity) |
106 | { |
107 | return insertImpl(entity, false); |
108 | } |
109 | |
110 | |
111 | std::vector<UUID> IAccessStorage::insert(const std::vector<AccessEntityPtr> & multiple_entities) |
112 | { |
113 | std::vector<UUID> ids; |
114 | ids.reserve(multiple_entities.size()); |
115 | String error_message; |
116 | for (const auto & entity : multiple_entities) |
117 | { |
118 | try |
119 | { |
120 | ids.push_back(insertImpl(entity, false)); |
121 | } |
122 | catch (Exception & e) |
123 | { |
124 | if (e.code() != ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS) |
125 | throw; |
126 | error_message += (error_message.empty() ? "" : ". " ) + e.message(); |
127 | } |
128 | } |
129 | if (!error_message.empty()) |
130 | throw Exception(error_message, ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS); |
131 | return ids; |
132 | } |
133 | |
134 | |
135 | std::optional<UUID> IAccessStorage::tryInsert(const AccessEntityPtr & entity) |
136 | { |
137 | try |
138 | { |
139 | return insertImpl(entity, false); |
140 | } |
141 | catch (Exception &) |
142 | { |
143 | return {}; |
144 | } |
145 | } |
146 | |
147 | |
148 | std::vector<UUID> IAccessStorage::tryInsert(const std::vector<AccessEntityPtr> & multiple_entities) |
149 | { |
150 | std::vector<UUID> ids; |
151 | ids.reserve(multiple_entities.size()); |
152 | for (const auto & entity : multiple_entities) |
153 | { |
154 | try |
155 | { |
156 | ids.push_back(insertImpl(entity, false)); |
157 | } |
158 | catch (Exception &) |
159 | { |
160 | } |
161 | } |
162 | return ids; |
163 | } |
164 | |
165 | |
166 | UUID IAccessStorage::insertOrReplace(const AccessEntityPtr & entity) |
167 | { |
168 | return insertImpl(entity, true); |
169 | } |
170 | |
171 | |
172 | std::vector<UUID> IAccessStorage::insertOrReplace(const std::vector<AccessEntityPtr> & multiple_entities) |
173 | { |
174 | std::vector<UUID> ids; |
175 | ids.reserve(multiple_entities.size()); |
176 | for (const auto & entity : multiple_entities) |
177 | ids.push_back(insertImpl(entity, true)); |
178 | return ids; |
179 | } |
180 | |
181 | |
182 | void IAccessStorage::remove(const UUID & id) |
183 | { |
184 | removeImpl(id); |
185 | } |
186 | |
187 | |
188 | void IAccessStorage::remove(const std::vector<UUID> & ids) |
189 | { |
190 | String error_message; |
191 | for (const auto & id : ids) |
192 | { |
193 | try |
194 | { |
195 | removeImpl(id); |
196 | } |
197 | catch (Exception & e) |
198 | { |
199 | if (e.code() != ErrorCodes::ACCESS_ENTITY_NOT_FOUND) |
200 | throw; |
201 | error_message += (error_message.empty() ? "" : ". " ) + e.message(); |
202 | } |
203 | } |
204 | if (!error_message.empty()) |
205 | throw Exception(error_message, ErrorCodes::ACCESS_ENTITY_NOT_FOUND); |
206 | } |
207 | |
208 | |
209 | bool IAccessStorage::tryRemove(const UUID & id) |
210 | { |
211 | try |
212 | { |
213 | removeImpl(id); |
214 | return true; |
215 | } |
216 | catch (Exception &) |
217 | { |
218 | return false; |
219 | } |
220 | } |
221 | |
222 | |
223 | std::vector<UUID> IAccessStorage::tryRemove(const std::vector<UUID> & ids) |
224 | { |
225 | std::vector<UUID> removed; |
226 | removed.reserve(ids.size()); |
227 | for (const auto & id : ids) |
228 | { |
229 | try |
230 | { |
231 | removeImpl(id); |
232 | removed.push_back(id); |
233 | } |
234 | catch (Exception &) |
235 | { |
236 | } |
237 | } |
238 | return removed; |
239 | } |
240 | |
241 | |
242 | void IAccessStorage::update(const UUID & id, const UpdateFunc & update_func) |
243 | { |
244 | updateImpl(id, update_func); |
245 | } |
246 | |
247 | |
248 | void IAccessStorage::update(const std::vector<UUID> & ids, const UpdateFunc & update_func) |
249 | { |
250 | String error_message; |
251 | for (const auto & id : ids) |
252 | { |
253 | try |
254 | { |
255 | updateImpl(id, update_func); |
256 | } |
257 | catch (Exception & e) |
258 | { |
259 | if (e.code() != ErrorCodes::ACCESS_ENTITY_NOT_FOUND) |
260 | throw; |
261 | error_message += (error_message.empty() ? "" : ". " ) + e.message(); |
262 | } |
263 | } |
264 | if (!error_message.empty()) |
265 | throw Exception(error_message, ErrorCodes::ACCESS_ENTITY_NOT_FOUND); |
266 | } |
267 | |
268 | |
269 | bool IAccessStorage::tryUpdate(const UUID & id, const UpdateFunc & update_func) |
270 | { |
271 | try |
272 | { |
273 | updateImpl(id, update_func); |
274 | return true; |
275 | } |
276 | catch (Exception &) |
277 | { |
278 | return false; |
279 | } |
280 | } |
281 | |
282 | |
283 | std::vector<UUID> IAccessStorage::tryUpdate(const std::vector<UUID> & ids, const UpdateFunc & update_func) |
284 | { |
285 | std::vector<UUID> updated; |
286 | updated.reserve(ids.size()); |
287 | for (const auto & id : ids) |
288 | { |
289 | try |
290 | { |
291 | updateImpl(id, update_func); |
292 | updated.push_back(id); |
293 | } |
294 | catch (Exception &) |
295 | { |
296 | } |
297 | } |
298 | return updated; |
299 | } |
300 | |
301 | |
302 | IAccessStorage::SubscriptionPtr IAccessStorage::subscribeForChanges(std::type_index type, const OnChangedHandler & handler) const |
303 | { |
304 | return subscribeForChangesImpl(type, handler); |
305 | } |
306 | |
307 | |
308 | IAccessStorage::SubscriptionPtr IAccessStorage::subscribeForChanges(const UUID & id, const OnChangedHandler & handler) const |
309 | { |
310 | return subscribeForChangesImpl(id, handler); |
311 | } |
312 | |
313 | |
314 | IAccessStorage::SubscriptionPtr IAccessStorage::subscribeForChanges(const std::vector<UUID> & ids, const OnChangedHandler & handler) const |
315 | { |
316 | if (ids.empty()) |
317 | return nullptr; |
318 | if (ids.size() == 1) |
319 | return subscribeForChangesImpl(ids[0], handler); |
320 | |
321 | std::vector<SubscriptionPtr> subscriptions; |
322 | subscriptions.reserve(ids.size()); |
323 | for (const auto & id : ids) |
324 | { |
325 | auto subscription = subscribeForChangesImpl(id, handler); |
326 | if (subscription) |
327 | subscriptions.push_back(std::move(subscription)); |
328 | } |
329 | |
330 | class SubscriptionImpl : public Subscription |
331 | { |
332 | public: |
333 | SubscriptionImpl(std::vector<SubscriptionPtr> subscriptions_) |
334 | : subscriptions(std::move(subscriptions_)) {} |
335 | private: |
336 | std::vector<SubscriptionPtr> subscriptions; |
337 | }; |
338 | |
339 | return std::make_unique<SubscriptionImpl>(std::move(subscriptions)); |
340 | } |
341 | |
342 | |
343 | bool IAccessStorage::hasSubscription(std::type_index type) const |
344 | { |
345 | return hasSubscriptionImpl(type); |
346 | } |
347 | |
348 | |
349 | bool IAccessStorage::hasSubscription(const UUID & id) const |
350 | { |
351 | return hasSubscriptionImpl(id); |
352 | } |
353 | |
354 | |
355 | void IAccessStorage::notify(const Notifications & notifications) |
356 | { |
357 | for (const auto & [fn, id, new_entity] : notifications) |
358 | fn(id, new_entity); |
359 | } |
360 | |
361 | |
362 | UUID IAccessStorage::generateRandomID() |
363 | { |
364 | static Poco::UUIDGenerator generator; |
365 | UUID id; |
366 | generator.createRandom().copyTo(reinterpret_cast<char *>(&id)); |
367 | return id; |
368 | } |
369 | |
370 | |
371 | Poco::Logger * IAccessStorage::getLogger() const |
372 | { |
373 | Poco::Logger * ptr = log.load(); |
374 | if (!ptr) |
375 | log.store(ptr = &Poco::Logger::get("Access(" + storage_name + ")" ), std::memory_order_relaxed); |
376 | return ptr; |
377 | } |
378 | |
379 | |
380 | void IAccessStorage::throwNotFound(const UUID & id) const |
381 | { |
382 | throw Exception("ID {" + toString(id) + "} not found in " + getStorageName(), ErrorCodes::ACCESS_ENTITY_NOT_FOUND); |
383 | } |
384 | |
385 | |
386 | void IAccessStorage::throwNotFound(std::type_index type, const String & name) const |
387 | { |
388 | throw Exception( |
389 | getTypeName(type) + " " + backQuote(name) + " not found in " + getStorageName(), ErrorCodes::ACCESS_ENTITY_NOT_FOUND); |
390 | } |
391 | |
392 | |
393 | void IAccessStorage::throwBadCast(const UUID & id, std::type_index type, const String & name, std::type_index required_type) const |
394 | { |
395 | throw Exception( |
396 | "ID {" + toString(id) + "}: " + getTypeName(type) + backQuote(name) + " expected to be of type " + getTypeName(required_type), |
397 | ErrorCodes::BAD_CAST); |
398 | } |
399 | |
400 | |
401 | void IAccessStorage::throwIDCollisionCannotInsert(const UUID & id, std::type_index type, const String & name, std::type_index existing_type, const String & existing_name) const |
402 | { |
403 | throw Exception( |
404 | getTypeName(type) + " " + backQuote(name) + ": cannot insert because the ID {" + toString(id) + "} is already used by " |
405 | + getTypeName(existing_type) + " " + backQuote(existing_name) + " in " + getStorageName(), |
406 | ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS); |
407 | } |
408 | |
409 | |
410 | void IAccessStorage::throwNameCollisionCannotInsert(std::type_index type, const String & name) const |
411 | { |
412 | throw Exception( |
413 | getTypeName(type) + " " + backQuote(name) + ": cannot insert because " + getTypeName(type) + " " + backQuote(name) |
414 | + " already exists in " + getStorageName(), |
415 | ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS); |
416 | } |
417 | |
418 | |
419 | void IAccessStorage::throwNameCollisionCannotRename(std::type_index type, const String & old_name, const String & new_name) const |
420 | { |
421 | throw Exception( |
422 | getTypeName(type) + " " + backQuote(old_name) + ": cannot rename to " + backQuote(new_name) + " because " + getTypeName(type) + " " |
423 | + backQuote(new_name) + " already exists in " + getStorageName(), |
424 | ErrorCodes::ACCESS_ENTITY_ALREADY_EXISTS); |
425 | } |
426 | |
427 | |
428 | void IAccessStorage::throwReadonlyCannotInsert(std::type_index type, const String & name) const |
429 | { |
430 | throw Exception( |
431 | "Cannot insert " + getTypeName(type) + " " + backQuote(name) + " to " + getStorageName() + " because this storage is readonly" , |
432 | ErrorCodes::ACCESS_ENTITY_STORAGE_READONLY); |
433 | } |
434 | |
435 | |
436 | void IAccessStorage::throwReadonlyCannotUpdate(std::type_index type, const String & name) const |
437 | { |
438 | throw Exception( |
439 | "Cannot update " + getTypeName(type) + " " + backQuote(name) + " in " + getStorageName() + " because this storage is readonly" , |
440 | ErrorCodes::ACCESS_ENTITY_STORAGE_READONLY); |
441 | } |
442 | |
443 | |
444 | void IAccessStorage::throwReadonlyCannotRemove(std::type_index type, const String & name) const |
445 | { |
446 | throw Exception( |
447 | "Cannot remove " + getTypeName(type) + " " + backQuote(name) + " from " + getStorageName() + " because this storage is readonly" , |
448 | ErrorCodes::ACCESS_ENTITY_STORAGE_READONLY); |
449 | } |
450 | } |
451 | |