]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // Copyright (c) 2011-present, Facebook, Inc. 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 | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. | |
6 | // Use of this source code is governed by a BSD-style license that can be | |
7 | // found in the LICENSE file. See the AUTHORS file for names of contributors. | |
8 | ||
9 | #pragma once | |
10 | ||
11 | #include "rocksdb/configurable.h" | |
12 | #include "rocksdb/status.h" | |
13 | ||
14 | namespace ROCKSDB_NAMESPACE { | |
15 | /** | |
16 | * Customizable a base class used by the rocksdb that describes a | |
17 | * standard way of configuring and creating objects. Customizable objects | |
18 | * are configurable objects that can be created from an ObjectRegistry. | |
19 | * | |
20 | * Customizable classes are used when there are multiple potential | |
21 | * implementations of a class for use by RocksDB (e.g. Table, Cache, | |
22 | * MergeOperator, etc). The abstract base class is expected to define a method | |
23 | * declaring its type and a factory method for creating one of these, such as: | |
24 | * static const char *Type() { return "Table"; } | |
25 | * static Status CreateFromString(const ConfigOptions& options, | |
26 | * const std::string& id, | |
27 | * std::shared_ptr<TableFactory>* result); | |
28 | * The "Type" string is expected to be unique (no two base classes are the same | |
29 | * type). This factory is expected, based on the options and id, create and | |
30 | * return the appropriate derived type of the customizable class (e.g. | |
31 | * BlockBasedTableFactory, PlainTableFactory, etc). For extension developers, | |
32 | * helper classes and methods are provided for writing this factory. | |
33 | * | |
34 | * Instances of a Customizable class need to define: | |
35 | * - A "static const char *kClassName()" method. This method defines the name | |
36 | * of the class instance (e.g. BlockBasedTable, LRUCache) and is used by the | |
37 | * CheckedCast method. | |
38 | * - The Name() of the object. This name is used when creating and saving | |
39 | * instances of this class. Typically this name will be the same as | |
40 | * kClassName(). | |
41 | * | |
42 | * Additionally, Customizable classes should register any options used to | |
43 | * configure themselves with the Configurable subsystem. | |
44 | * | |
45 | * When a Customizable is being created, the "name" property specifies | |
46 | * the name of the instance being created. | |
47 | * For custom objects, their configuration and name can be specified by: | |
48 | * [prop]={name=X;option 1 = value1[; option2=value2...]} | |
49 | * | |
50 | * [prop].name=X | |
51 | * [prop].option1 = value1 | |
52 | * | |
53 | * [prop].name=X | |
54 | * X.option1 =value1 | |
55 | */ | |
56 | class Customizable : public Configurable { | |
57 | public: | |
1e59de90 | 58 | ~Customizable() override {} |
20effc67 TL |
59 | |
60 | // Returns the name of this class of Customizable | |
61 | virtual const char* Name() const = 0; | |
62 | ||
63 | // Returns an identifier for this Customizable. | |
64 | // This could be its name or something more complex (like its URL/pattern). | |
65 | // Used for pretty printing. | |
66 | virtual std::string GetId() const { | |
67 | std::string id = Name(); | |
68 | return id; | |
69 | } | |
70 | ||
71 | // This is typically determined by if the input name matches the | |
72 | // name of this object. | |
73 | // This method is typically used in conjunction with CheckedCast to find the | |
74 | // derived class instance from its base. For example, if you have an Env | |
75 | // and want the "Default" env, you would IsInstanceOf("Default") to get | |
76 | // the default implementation. This method should be used when you need a | |
77 | // specific derivative or implementation of a class. | |
78 | // | |
79 | // Intermediary caches (such as SharedCache) may wish to override this method | |
80 | // to check for the intermediary name (SharedCache). Classes with multiple | |
81 | // potential names (e.g. "PosixEnv", "DefaultEnv") may also wish to override | |
82 | // this method. | |
83 | // | |
1e59de90 TL |
84 | // Note that IsInstanceOf only uses the "is-a" relationship and not "has-a". |
85 | // Wrapped classes that have an Inner "has-a" should not be returned. | |
86 | // | |
20effc67 TL |
87 | // @param name The name of the instance to find. |
88 | // Returns true if the class is an instance of the input name. | |
89 | virtual bool IsInstanceOf(const std::string& name) const { | |
1e59de90 TL |
90 | if (name.empty()) { |
91 | return false; | |
92 | } else if (name == Name()) { | |
93 | return true; | |
94 | } else { | |
95 | const char* nickname = NickName(); | |
96 | if (nickname != nullptr && name == nickname) { | |
97 | return true; | |
98 | } else { | |
99 | return false; | |
100 | } | |
101 | } | |
102 | } | |
103 | ||
104 | const void* GetOptionsPtr(const std::string& name) const override { | |
105 | const void* ptr = Configurable::GetOptionsPtr(name); | |
106 | if (ptr != nullptr) { | |
107 | return ptr; | |
108 | } else { | |
109 | const auto inner = Inner(); | |
110 | if (inner != nullptr) { | |
111 | return inner->GetOptionsPtr(name); | |
112 | } else { | |
113 | return nullptr; | |
114 | } | |
115 | } | |
20effc67 TL |
116 | } |
117 | ||
118 | // Returns the named instance of the Customizable as a T*, or nullptr if not | |
1e59de90 TL |
119 | // found. This method uses IsInstanceOf/Inner to find the appropriate class |
120 | // instance and then casts it to the expected return type. | |
20effc67 TL |
121 | template <typename T> |
122 | const T* CheckedCast() const { | |
123 | if (IsInstanceOf(T::kClassName())) { | |
124 | return static_cast<const T*>(this); | |
125 | } else { | |
1e59de90 TL |
126 | const auto inner = Inner(); |
127 | if (inner != nullptr) { | |
128 | return inner->CheckedCast<T>(); | |
129 | } else { | |
130 | return nullptr; | |
131 | } | |
20effc67 TL |
132 | } |
133 | } | |
134 | ||
135 | template <typename T> | |
136 | T* CheckedCast() { | |
137 | if (IsInstanceOf(T::kClassName())) { | |
138 | return static_cast<T*>(this); | |
139 | } else { | |
1e59de90 TL |
140 | auto inner = const_cast<Customizable*>(Inner()); |
141 | if (inner != nullptr) { | |
142 | return inner->CheckedCast<T>(); | |
143 | } else { | |
144 | return nullptr; | |
145 | } | |
20effc67 TL |
146 | } |
147 | } | |
148 | ||
149 | // Checks to see if this Customizable is equivalent to other. | |
150 | // This method assumes that the two objects are of the same class. | |
151 | // @param config_options Controls how the options are compared. | |
152 | // @param other The other object to compare to. | |
153 | // @param mismatch If the objects do not match, this parameter contains | |
154 | // the name of the option that triggered the match failure. | |
155 | // @param True if the objects match, false otherwise. | |
156 | // @see Configurable::AreEquivalent for more details | |
157 | bool AreEquivalent(const ConfigOptions& config_options, | |
158 | const Configurable* other, | |
159 | std::string* mismatch) const override; | |
160 | #ifndef ROCKSDB_LITE | |
161 | // Gets the value of the option associated with the input name | |
162 | // @see Configurable::GetOption for more details | |
163 | Status GetOption(const ConfigOptions& config_options, const std::string& name, | |
164 | std::string* value) const override; | |
20effc67 | 165 | #endif // ROCKSDB_LITE |
1e59de90 TL |
166 | // Helper method for getting for parsing the opt_value into the corresponding |
167 | // options for use in potentially creating a new Customizable object (this | |
168 | // method is primarily a support method for LoadSharedObject et al for new | |
169 | // Customizable objects). The opt_value may be either name-value pairs | |
170 | // separated by ";" (a=b; c=d), or a simple name (a). In order to create a new | |
171 | // Customizable, the ID is determined by: | |
172 | // - If the value is a simple name (e.g. "BlockBasedTable"), the id is this | |
173 | // name; | |
174 | // - Otherwise, if there is a "id=value", the id is set to "value" | |
175 | // - Otherwise, if the input customizable is not null, custom->GetId is used | |
176 | // - Otherwise, an error is returned. | |
177 | // | |
178 | // If the opt_value is name-value pairs, these pairs will be returned in | |
179 | // options (without the id pair). If the ID being returned matches the ID of | |
180 | // the input custom object, then the options from the input object will also | |
181 | // be added to the returned options. | |
182 | // | |
183 | // This method returns non-OK if the ID could not be found, or if the | |
184 | // opt_value could not be parsed into name-value pairs. | |
185 | static Status GetOptionsMap( | |
186 | const ConfigOptions& config_options, const Customizable* custom, | |
187 | const std::string& opt_value, std::string* id, | |
188 | std::unordered_map<std::string, std::string>* options); | |
189 | ||
190 | // Helper method to configure a new object with the supplied options. | |
191 | // If the object is not null and invoke_prepare_options=true, the object | |
192 | // will be configured and prepared. | |
193 | // Returns success if the object is properly configured and (optionally) | |
194 | // prepared Returns InvalidArgument if the object is nullptr and there are | |
195 | // options in the map Returns the result of the ConfigureFromMap or | |
196 | // PrepareOptions | |
197 | static Status ConfigureNewObject( | |
198 | const ConfigOptions& config_options, Customizable* object, | |
199 | const std::unordered_map<std::string, std::string>& options); | |
200 | ||
201 | // Returns the inner class when a Customizable implements a has-a (wrapped) | |
202 | // relationship. Derived classes that implement a has-a must override this | |
203 | // method in order to get CheckedCast to function properly. | |
204 | virtual const Customizable* Inner() const { return nullptr; } | |
205 | ||
20effc67 | 206 | protected: |
1e59de90 TL |
207 | // Generates a ID specific for this instance of the customizable. |
208 | // The unique ID is of the form <name>:<addr>#pid, where: | |
209 | // - name is the Name() of this object; | |
210 | // - addr is the memory address of this object; | |
211 | // - pid is the process ID of this process ID for this process. | |
212 | // Note that if obj1 and obj2 have the same unique IDs, they must be the | |
213 | // same. However, if an object is deleted and recreated, it may have the | |
214 | // same unique ID as a predecessor | |
215 | // | |
216 | // This method is useful for objects (especially ManagedObjects) that | |
217 | // wish to generate an ID that is specific for this instance and wish to | |
218 | // override the GetId() method. | |
219 | std::string GenerateIndividualId() const; | |
220 | ||
221 | // Some classes have both a class name (e.g. PutOperator) and a nickname | |
222 | // (e.g. put). Classes can override this method to return a | |
223 | // nickname. Nicknames can be used by InstanceOf and object creation. | |
224 | virtual const char* NickName() const { return ""; } | |
20effc67 TL |
225 | // Given a name (e.g. rocksdb.my.type.opt), returns the short name (opt) |
226 | std::string GetOptionName(const std::string& long_name) const override; | |
227 | #ifndef ROCKSDB_LITE | |
228 | std::string SerializeOptions(const ConfigOptions& options, | |
229 | const std::string& prefix) const override; | |
230 | #endif // ROCKSDB_LITE | |
231 | }; | |
232 | ||
233 | } // namespace ROCKSDB_NAMESPACE |