1#include <Access/MultipleAccessStorage.h>
2#include <Common/Exception.h>
3#include <Common/quoteString.h>
4
5
6namespace DB
7{
8namespace ErrorCodes
9{
10 extern const int ACCESS_ENTITY_NOT_FOUND;
11 extern const int ACCESS_ENTITY_FOUND_DUPLICATES;
12}
13
14
15namespace
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
32MultipleAccessStorage::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
42MultipleAccessStorage::~MultipleAccessStorage()
43{
44}
45
46
47std::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
64std::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
87std::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
99bool MultipleAccessStorage::existsImpl(const UUID & id) const
100{
101 return findStorage(id) != nullptr;
102}
103
104
105IAccessStorage * 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
132const IAccessStorage * MultipleAccessStorage::findStorage(const UUID & id) const
133{
134 return const_cast<MultipleAccessStorage *>(this)->findStorage(id);
135}
136
137
138IAccessStorage & MultipleAccessStorage::getStorage(const UUID & id)
139{
140 auto * storage = findStorage(id);
141 if (storage)
142 return *storage;
143 throwNotFound(id);
144}
145
146
147const IAccessStorage & MultipleAccessStorage::getStorage(const UUID & id) const
148{
149 return const_cast<MultipleAccessStorage *>(this)->getStorage(id);
150}
151
152
153AccessEntityPtr MultipleAccessStorage::readImpl(const UUID & id) const
154{
155 return getStorage(id).read(id);
156}
157
158
159String MultipleAccessStorage::readNameImpl(const UUID & id) const
160{
161 return getStorage(id).readName(id);
162}
163
164
165UUID 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
176void MultipleAccessStorage::removeImpl(const UUID & id)
177{
178 getStorage(id).remove(id);
179}
180
181
182void MultipleAccessStorage::updateImpl(const UUID & id, const UpdateFunc & update_func)
183{
184 getStorage(id).update(id, update_func);
185}
186
187
188IAccessStorage::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
197IAccessStorage::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
226bool 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
237bool 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