Coverage Report

Created: 2024-07-27 06:53

/src/rocksdb/utilities/object_registry.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
2
//  This source code is licensed under both the GPLv2 (found in the
3
//  COPYING file in the root directory) and Apache 2.0 License
4
//  (found in the LICENSE.Apache file in the root directory).
5
6
#include "rocksdb/utilities/object_registry.h"
7
8
#include <cctype>
9
10
#include "logging/logging.h"
11
#include "port/lang.h"
12
#include "rocksdb/customizable.h"
13
#include "rocksdb/env.h"
14
#include "util/string_util.h"
15
16
namespace ROCKSDB_NAMESPACE {
17
namespace {
18
0
bool MatchesInteger(const std::string &target, size_t start, size_t pos) {
19
  // If it is numeric, everything up to the match must be a number
20
0
  int digits = 0;
21
0
  if (target[start] == '-') {
22
0
    start++;  // Allow negative numbers
23
0
  }
24
0
  while (start < pos) {
25
0
    if (!isdigit(target[start++])) {
26
0
      return false;
27
0
    } else {
28
0
      digits++;
29
0
    }
30
0
  }
31
0
  return (digits > 0);
32
0
}
33
34
0
bool MatchesDecimal(const std::string &target, size_t start, size_t pos) {
35
0
  int digits = 0;
36
0
  if (target[start] == '-') {
37
0
    start++;  // Allow negative numbers
38
0
  }
39
0
  for (bool point = false; start < pos; start++) {
40
0
    if (target[start] == '.') {
41
0
      if (point) {
42
0
        return false;
43
0
      } else {
44
0
        point = true;
45
0
      }
46
0
    } else if (!isdigit(target[start])) {
47
0
      return false;
48
0
    } else {
49
0
      digits++;
50
0
    }
51
0
  }
52
0
  return (digits > 0);
53
0
}
54
}  // namespace
55
56
size_t ObjectLibrary::PatternEntry::MatchSeparatorAt(
57
    size_t start, Quantifier mode, const std::string &target, size_t tlen,
58
0
    const std::string &separator) const {
59
0
  size_t slen = separator.size();
60
  // See if there is enough space.  If so, find the separator
61
0
  if (tlen < start + slen) {
62
0
    return std::string::npos;  // not enough space left
63
0
  } else if (mode == kMatchExact) {
64
    // Exact mode means the next thing we are looking for is the separator
65
0
    if (target.compare(start, slen, separator) != 0) {
66
0
      return std::string::npos;
67
0
    } else {
68
0
      return start + slen;  // Found the separator, return where we found it
69
0
    }
70
0
  } else {
71
0
    auto pos = start + 1;
72
0
    if (!separator.empty()) {
73
0
      pos = target.find(separator, pos);
74
0
    }
75
0
    if (pos == std::string::npos) {
76
0
      return pos;
77
0
    } else if (mode == kMatchInteger) {
78
0
      if (!MatchesInteger(target, start, pos)) {
79
0
        return std::string::npos;
80
0
      }
81
0
    } else if (mode == kMatchDecimal) {
82
0
      if (!MatchesDecimal(target, start, pos)) {
83
0
        return std::string::npos;
84
0
      }
85
0
    }
86
0
    return pos + slen;
87
0
  }
88
0
}
89
90
bool ObjectLibrary::PatternEntry::MatchesTarget(const std::string &name,
91
                                                size_t nlen,
92
                                                const std::string &target,
93
265k
                                                size_t tlen) const {
94
265k
  if (separators_.empty()) {
95
151k
    assert(optional_);  // If there are no separators, it must be only a name
96
151k
    return nlen == tlen && name == target;
97
151k
  } else if (nlen == tlen) {  // The lengths are the same
98
37.8k
    return optional_ && name == target;
99
75.7k
  } else if (tlen < nlen + slength_) {
100
    // The target is not long enough
101
37.8k
    return false;
102
37.8k
  } else if (target.compare(0, nlen, name) != 0) {
103
37.8k
    return false;  // Target does not start with name
104
37.8k
  } else {
105
    // Loop through all of the separators one at a time matching them.
106
    // Note that we first match the separator and then its quantifiers.
107
    // Since we expect the separator first, we start with an exact match
108
    // Subsequent matches will use the quantifier of the previous separator
109
0
    size_t start = nlen;
110
0
    auto mode = kMatchExact;
111
0
    for (size_t idx = 0; idx < separators_.size(); ++idx) {
112
0
      const auto &separator = separators_[idx];
113
0
      start = MatchSeparatorAt(start, mode, target, tlen, separator.first);
114
0
      if (start == std::string::npos) {
115
0
        return false;
116
0
      } else {
117
0
        mode = separator.second;
118
0
      }
119
0
    }
120
    // We have matched all of the separators.  Now check that what is left
121
    // unmatched in the target is acceptable.
122
0
    if (mode == kMatchExact) {
123
0
      return (start == tlen);
124
0
    } else if (start > tlen || (start == tlen && mode != kMatchZeroOrMore)) {
125
0
      return false;
126
0
    } else if (mode == kMatchInteger) {
127
0
      return MatchesInteger(target, start, tlen);
128
0
    } else if (mode == kMatchDecimal) {
129
0
      return MatchesDecimal(target, start, tlen);
130
0
    }
131
0
  }
132
0
  return true;
133
265k
}
134
135
227k
bool ObjectLibrary::PatternEntry::Matches(const std::string &target) const {
136
227k
  auto tlen = target.size();
137
227k
  if (MatchesTarget(name_, nlength_, target, tlen)) {
138
189k
    return true;
139
189k
  } else if (!names_.empty()) {
140
37.8k
    for (const auto &alt : names_) {
141
37.8k
      if (MatchesTarget(alt, alt.size(), target, tlen)) {
142
0
        return true;
143
0
      }
144
37.8k
    }
145
37.8k
  }
146
37.8k
  return false;
147
227k
}
148
149
3
size_t ObjectLibrary::GetFactoryCount(size_t *types) const {
150
3
  std::unique_lock<std::mutex> lock(mu_);
151
3
  *types = factories_.size();
152
3
  size_t factories = 0;
153
21
  for (const auto &e : factories_) {
154
21
    factories += e.second.size();
155
21
  }
156
3
  return factories;
157
3
}
158
159
0
size_t ObjectLibrary::GetFactoryCount(const std::string &type) const {
160
0
  std::unique_lock<std::mutex> lock(mu_);
161
0
  auto iter = factories_.find(type);
162
0
  if (iter != factories_.end()) {
163
0
    return iter->second.size();
164
0
  } else {
165
0
    return 0;
166
0
  }
167
0
}
168
169
void ObjectLibrary::GetFactoryNames(const std::string &type,
170
0
                                    std::vector<std::string> *names) const {
171
0
  assert(names);
172
0
  std::unique_lock<std::mutex> lock(mu_);
173
0
  auto iter = factories_.find(type);
174
0
  if (iter != factories_.end()) {
175
0
    for (const auto &f : iter->second) {
176
0
      names->push_back(f->Name());
177
0
    }
178
0
  }
179
0
}
180
181
void ObjectLibrary::GetFactoryTypes(
182
0
    std::unordered_set<std::string> *types) const {
183
0
  assert(types);
184
0
  std::unique_lock<std::mutex> lock(mu_);
185
0
  for (const auto &iter : factories_) {
186
0
    types->insert(iter.first);
187
0
  }
188
0
}
189
190
0
void ObjectLibrary::Dump(Logger *logger) const {
191
0
  std::unique_lock<std::mutex> lock(mu_);
192
0
  if (logger != nullptr && !factories_.empty()) {
193
0
    ROCKS_LOG_HEADER(logger, "    Registered Library: %s\n", id_.c_str());
194
0
    for (const auto &iter : factories_) {
195
0
      ROCKS_LOG_HEADER(logger, "    Registered factories for type[%s] ",
196
0
                       iter.first.c_str());
197
0
      bool printed_one = false;
198
0
      for (const auto &e : iter.second) {
199
0
        ROCKS_LOG_HEADER(logger, "%c %s", (printed_one) ? ',' : ':', e->Name());
200
0
        printed_one = true;
201
0
      }
202
0
    }
203
0
  }
204
0
}
205
206
// Returns the Default singleton instance of the ObjectLibrary
207
// This instance will contain most of the "standard" registered objects
208
12
std::shared_ptr<ObjectLibrary> &ObjectLibrary::Default() {
209
  // Use avoid destruction here so the default ObjectLibrary will not be
210
  // statically destroyed and long-lived.
211
12
  STATIC_AVOID_DESTRUCTION(std::shared_ptr<ObjectLibrary>, instance)
212
12
  (std::make_shared<ObjectLibrary>("default"));
213
12
  return instance;
214
12
}
215
216
1
ObjectRegistry::ObjectRegistry(const std::shared_ptr<ObjectLibrary> &library) {
217
1
  libraries_.push_back(library);
218
1
  for (const auto &b : builtins_) {
219
0
    RegisterPlugin(b.first, b.second);
220
0
  }
221
1
}
222
223
52.2k
std::shared_ptr<ObjectRegistry> ObjectRegistry::Default() {
224
  // Use avoid destruction here so the default ObjectRegistry will not be
225
  // statically destroyed and long-lived.
226
52.2k
  STATIC_AVOID_DESTRUCTION(std::shared_ptr<ObjectRegistry>, instance)
227
52.2k
  (std::make_shared<ObjectRegistry>(ObjectLibrary::Default()));
228
52.2k
  return instance;
229
52.2k
}
230
231
52.2k
std::shared_ptr<ObjectRegistry> ObjectRegistry::NewInstance() {
232
52.2k
  return std::make_shared<ObjectRegistry>(Default());
233
52.2k
}
234
235
std::shared_ptr<ObjectRegistry> ObjectRegistry::NewInstance(
236
0
    const std::shared_ptr<ObjectRegistry> &parent) {
237
0
  return std::make_shared<ObjectRegistry>(parent);
238
0
}
239
240
Status ObjectRegistry::SetManagedObject(
241
    const std::string &type, const std::string &id,
242
0
    const std::shared_ptr<Customizable> &object) {
243
0
  std::string object_key = ToManagedObjectKey(type, id);
244
0
  std::shared_ptr<Customizable> curr;
245
0
  if (parent_ != nullptr) {
246
0
    curr = parent_->GetManagedObject(type, id);
247
0
  }
248
0
  if (curr == nullptr) {
249
    // We did not find the object in any parent.  Update in the current
250
0
    std::unique_lock<std::mutex> lock(objects_mutex_);
251
0
    auto iter = managed_objects_.find(object_key);
252
0
    if (iter != managed_objects_.end()) {  // The object exists
253
0
      curr = iter->second.lock();
254
0
      if (curr != nullptr && curr != object) {
255
0
        return Status::InvalidArgument("Object already exists: ", object_key);
256
0
      } else {
257
0
        iter->second = object;
258
0
      }
259
0
    } else {
260
      // The object does not exist.  Add it
261
0
      managed_objects_[object_key] = object;
262
0
    }
263
0
  } else if (curr != object) {
264
0
    return Status::InvalidArgument("Object already exists: ", object_key);
265
0
  }
266
0
  return Status::OK();
267
0
}
268
269
std::shared_ptr<Customizable> ObjectRegistry::GetManagedObject(
270
0
    const std::string &type, const std::string &id) const {
271
0
  {
272
0
    std::unique_lock<std::mutex> lock(objects_mutex_);
273
0
    auto iter = managed_objects_.find(ToManagedObjectKey(type, id));
274
0
    if (iter != managed_objects_.end()) {
275
0
      return iter->second.lock();
276
0
    }
277
0
  }
278
0
  if (parent_ != nullptr) {
279
0
    return parent_->GetManagedObject(type, id);
280
0
  } else {
281
0
    return nullptr;
282
0
  }
283
0
}
284
285
Status ObjectRegistry::ListManagedObjects(
286
    const std::string &type, const std::string &name,
287
0
    std::vector<std::shared_ptr<Customizable>> *results) const {
288
0
  {
289
0
    std::string key = ToManagedObjectKey(type, name);
290
0
    std::unique_lock<std::mutex> lock(objects_mutex_);
291
0
    for (auto iter = managed_objects_.lower_bound(key);
292
0
         iter != managed_objects_.end() && StartsWith(iter->first, key);
293
0
         ++iter) {
294
0
      auto shared = iter->second.lock();
295
0
      if (shared != nullptr) {
296
0
        if (name.empty() || shared->IsInstanceOf(name)) {
297
0
          results->emplace_back(shared);
298
0
        }
299
0
      }
300
0
    }
301
0
  }
302
0
  if (parent_ != nullptr) {
303
0
    return parent_->ListManagedObjects(type, name, results);
304
0
  } else {
305
0
    return Status::OK();
306
0
  }
307
0
}
308
309
// Returns the number of registered types for this registry.
310
// If specified (not-null), types is updated to include the names of the
311
// registered types.
312
0
size_t ObjectRegistry::GetFactoryCount(const std::string &type) const {
313
0
  size_t count = 0;
314
0
  if (parent_ != nullptr) {
315
0
    count = parent_->GetFactoryCount(type);
316
0
  }
317
0
  std::unique_lock<std::mutex> lock(library_mutex_);
318
0
  for (const auto &library : libraries_) {
319
0
    count += library->GetFactoryCount(type);
320
0
  }
321
0
  return count;
322
0
}
323
324
void ObjectRegistry::GetFactoryNames(const std::string &type,
325
0
                                     std::vector<std::string> *names) const {
326
0
  assert(names);
327
0
  names->clear();
328
0
  if (parent_ != nullptr) {
329
0
    parent_->GetFactoryNames(type, names);
330
0
  }
331
0
  std::unique_lock<std::mutex> lock(library_mutex_);
332
0
  for (const auto &library : libraries_) {
333
0
    library->GetFactoryNames(type, names);
334
0
  }
335
0
}
336
337
void ObjectRegistry::GetFactoryTypes(
338
0
    std::unordered_set<std::string> *types) const {
339
0
  assert(types);
340
0
  if (parent_ != nullptr) {
341
0
    parent_->GetFactoryTypes(types);
342
0
  }
343
0
  std::unique_lock<std::mutex> lock(library_mutex_);
344
0
  for (const auto &library : libraries_) {
345
0
    library->GetFactoryTypes(types);
346
0
  }
347
0
}
348
349
0
void ObjectRegistry::Dump(Logger *logger) const {
350
0
  if (logger != nullptr) {
351
0
    std::unique_lock<std::mutex> lock(library_mutex_);
352
0
    if (!plugins_.empty()) {
353
0
      ROCKS_LOG_HEADER(logger, "    Registered Plugins:");
354
0
      bool printed_one = false;
355
0
      for (const auto &plugin : plugins_) {
356
0
        ROCKS_LOG_HEADER(logger, "%s%s", (printed_one) ? ", " : " ",
357
0
                         plugin.c_str());
358
0
        printed_one = true;
359
0
      }
360
0
      ROCKS_LOG_HEADER(logger, "\n");
361
0
    }
362
0
    for (auto iter = libraries_.crbegin(); iter != libraries_.crend(); ++iter) {
363
0
      iter->get()->Dump(logger);
364
0
    }
365
0
  }
366
0
  if (parent_ != nullptr) {
367
0
    parent_->Dump(logger);
368
0
  }
369
0
}
370
371
int ObjectRegistry::RegisterPlugin(const std::string &name,
372
0
                                   const RegistrarFunc &func) {
373
0
  if (!name.empty() && func != nullptr) {
374
0
    plugins_.push_back(name);
375
0
    return AddLibrary(name)->Register(func, name);
376
0
  } else {
377
0
    return -1;
378
0
  }
379
0
}
380
381
}  // namespace ROCKSDB_NAMESPACE