summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/include/rocksdb/customizable.h
blob: 92f7504ae1bb8b23a49ed51fdad55604f32513d9 (plain)
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
// Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#pragma once

#include "rocksdb/configurable.h"
#include "rocksdb/status.h"

namespace ROCKSDB_NAMESPACE {
/**
 * Customizable a base class used by the rocksdb that describes a
 * standard way of configuring and creating objects.  Customizable objects
 * are configurable objects that can be created from an ObjectRegistry.
 *
 * Customizable classes are used when there are multiple potential
 * implementations of a class for use by RocksDB (e.g. Table, Cache,
 * MergeOperator, etc).  The abstract base class is expected to define a method
 * declaring its type and a factory method for creating one of these, such as:
 * static const char *Type() { return "Table"; }
 * static Status CreateFromString(const ConfigOptions& options,
 *                                const std::string& id,
 *                                std::shared_ptr<TableFactory>* result);
 * The "Type" string is expected to be unique (no two base classes are the same
 * type). This factory is expected, based on the options and id, create and
 * return the appropriate derived type of the customizable class (e.g.
 * BlockBasedTableFactory, PlainTableFactory, etc). For extension developers,
 * helper classes and methods are provided for writing this factory.
 *
 * Instances of a Customizable class need to define:
 * - A "static const char *kClassName()" method.  This method defines the name
 * of the class instance (e.g. BlockBasedTable, LRUCache) and is used by the
 * CheckedCast method.
 * - The Name() of the object.  This name is used when creating and saving
 * instances of this class.  Typically this name will be the same as
 * kClassName().
 *
 * Additionally, Customizable classes should register any options used to
 * configure themselves with the Configurable subsystem.
 *
 * When a Customizable is being created, the "name" property specifies
 * the name of the instance being created.
 * For custom objects, their configuration and name can be specified by:
 * [prop]={name=X;option 1 = value1[; option2=value2...]}
 *
 * [prop].name=X
 * [prop].option1 = value1
 *
 * [prop].name=X
 * X.option1 =value1
 */
class Customizable : public Configurable {
 public:
  ~Customizable() override {}

  // Returns the name of this class of Customizable
  virtual const char* Name() const = 0;

  // Returns an identifier for this Customizable.
  // This could be its name or something more complex (like its URL/pattern).
  // Used for pretty printing.
  virtual std::string GetId() const {
    std::string id = Name();
    return id;
  }

  // This is typically determined by if the input name matches the
  // name of this object.
  // This method is typically used in conjunction with CheckedCast to find the
  // derived class instance from its base.  For example, if you have an Env
  // and want the "Default" env, you would IsInstanceOf("Default") to get
  // the default implementation.  This method should be used when you need a
  // specific derivative or implementation of a class.
  //
  // Intermediary caches (such as SharedCache) may wish to override this method
  // to check for the intermediary name (SharedCache).  Classes with multiple
  // potential names (e.g. "PosixEnv", "DefaultEnv") may also wish to override
  // this method.
  //
  // Note that IsInstanceOf only uses the "is-a" relationship and not "has-a".
  // Wrapped classes that have an Inner "has-a" should not be returned.
  //
  // @param name The name of the instance to find.
  // Returns true if the class is an instance of the input name.
  virtual bool IsInstanceOf(const std::string& name) const {
    if (name.empty()) {
      return false;
    } else if (name == Name()) {
      return true;
    } else {
      const char* nickname = NickName();
      if (nickname != nullptr && name == nickname) {
        return true;
      } else {
        return false;
      }
    }
  }

  const void* GetOptionsPtr(const std::string& name) const override {
    const void* ptr = Configurable::GetOptionsPtr(name);
    if (ptr != nullptr) {
      return ptr;
    } else {
      const auto inner = Inner();
      if (inner != nullptr) {
        return inner->GetOptionsPtr(name);
      } else {
        return nullptr;
      }
    }
  }

  // Returns the named instance of the Customizable as a T*, or nullptr if not
  // found. This method uses IsInstanceOf/Inner to find the appropriate class
  // instance and then casts it to the expected return type.
  template <typename T>
  const T* CheckedCast() const {
    if (IsInstanceOf(T::kClassName())) {
      return static_cast<const T*>(this);
    } else {
      const auto inner = Inner();
      if (inner != nullptr) {
        return inner->CheckedCast<T>();
      } else {
        return nullptr;
      }
    }
  }

  template <typename T>
  T* CheckedCast() {
    if (IsInstanceOf(T::kClassName())) {
      return static_cast<T*>(this);
    } else {
      auto inner = const_cast<Customizable*>(Inner());
      if (inner != nullptr) {
        return inner->CheckedCast<T>();
      } else {
        return nullptr;
      }
    }
  }

  // Checks to see if this Customizable is equivalent to other.
  // This method assumes that the two objects are of the same class.
  // @param config_options Controls how the options are compared.
  // @param other The other object to compare to.
  // @param mismatch If the objects do not match, this parameter contains
  //      the name of the option that triggered the match failure.
  // @param True if the objects match, false otherwise.
  // @see Configurable::AreEquivalent for more details
  bool AreEquivalent(const ConfigOptions& config_options,
                     const Configurable* other,
                     std::string* mismatch) const override;
#ifndef ROCKSDB_LITE
  // Gets the value of the option associated with the input name
  // @see Configurable::GetOption for more details
  Status GetOption(const ConfigOptions& config_options, const std::string& name,
                   std::string* value) const override;
#endif  // ROCKSDB_LITE
  // Helper method for getting for parsing the opt_value into the corresponding
  // options for use in potentially creating a new Customizable object (this
  // method is primarily a support method for LoadSharedObject et al for new
  // Customizable objects). The opt_value may be either name-value pairs
  // separated by ";" (a=b; c=d), or a simple name (a). In order to create a new
  // Customizable, the ID is determined by:
  // - If the value is a simple name (e.g. "BlockBasedTable"), the id is this
  // name;
  // - Otherwise, if there is a "id=value", the id is set to "value"
  // - Otherwise, if the input customizable is not null, custom->GetId is used
  // - Otherwise, an error is returned.
  //
  // If the opt_value is name-value pairs, these pairs will be returned in
  // options (without the id pair). If the ID being returned matches the ID of
  // the input custom object, then the options from the input object will also
  // be added to the returned options.
  //
  // This method returns non-OK if the ID could not be found, or if the
  // opt_value could not be parsed into name-value pairs.
  static Status GetOptionsMap(
      const ConfigOptions& config_options, const Customizable* custom,
      const std::string& opt_value, std::string* id,
      std::unordered_map<std::string, std::string>* options);

  // Helper method to configure a new object with the supplied options.
  // If the object is not null and invoke_prepare_options=true, the object
  // will be configured and prepared.
  // Returns success if the object is properly configured and (optionally)
  // prepared Returns InvalidArgument if the object is nullptr and there are
  // options in the map Returns the result of the ConfigureFromMap or
  // PrepareOptions
  static Status ConfigureNewObject(
      const ConfigOptions& config_options, Customizable* object,
      const std::unordered_map<std::string, std::string>& options);

  // Returns the inner class when a Customizable implements a has-a (wrapped)
  // relationship.  Derived classes that implement a has-a must override this
  // method in order to get CheckedCast to function properly.
  virtual const Customizable* Inner() const { return nullptr; }

 protected:
  // Generates a ID specific for this instance of the customizable.
  // The unique ID is of the form <name>:<addr>#pid, where:
  // - name is the Name() of this object;
  // - addr is the memory address of this object;
  // - pid is the process ID of this process ID for this process.
  // Note that if obj1 and obj2 have the same unique IDs, they must be the
  // same.  However, if an object is deleted and recreated, it may have the
  // same unique ID as a predecessor
  //
  // This method is useful for objects (especially ManagedObjects) that
  // wish to generate an ID that is specific for this instance and wish to
  // override the GetId() method.
  std::string GenerateIndividualId() const;

  // Some classes have both a class name (e.g. PutOperator) and a nickname
  // (e.g. put). Classes can override this method to return a
  // nickname.  Nicknames can be used by InstanceOf and object creation.
  virtual const char* NickName() const { return ""; }
  //  Given a name (e.g. rocksdb.my.type.opt), returns the short name (opt)
  std::string GetOptionName(const std::string& long_name) const override;
#ifndef ROCKSDB_LITE
  std::string SerializeOptions(const ConfigOptions& options,
                               const std::string& prefix) const override;
#endif  // ROCKSDB_LITE
};

}  // namespace ROCKSDB_NAMESPACE