1 | #pragma once |
2 | |
3 | #include <Core/Types.h> |
4 | #include <Common/Exception.h> |
5 | |
6 | #include <vector> |
7 | #include <memory> |
8 | #include <cstdint> |
9 | #include <functional> |
10 | |
11 | /** Generic interface for ZooKeeper-like services. |
12 | * Possible examples are: |
13 | * - ZooKeeper client itself; |
14 | * - fake ZooKeeper client for testing; |
15 | * - ZooKeeper emulation layer on top of Etcd, FoundationDB, whatever. |
16 | */ |
17 | |
18 | |
19 | namespace Coordination |
20 | { |
21 | |
22 | using namespace DB; |
23 | |
24 | |
25 | struct ACL |
26 | { |
27 | static constexpr int32_t Read = 1; |
28 | static constexpr int32_t Write = 2; |
29 | static constexpr int32_t Create = 4; |
30 | static constexpr int32_t Delete = 8; |
31 | static constexpr int32_t Admin = 16; |
32 | static constexpr int32_t All = 0x1F; |
33 | |
34 | int32_t permissions; |
35 | String scheme; |
36 | String id; |
37 | }; |
38 | |
39 | using ACLs = std::vector<ACL>; |
40 | |
41 | struct Stat |
42 | { |
43 | int64_t czxid; |
44 | int64_t mzxid; |
45 | int64_t ctime; |
46 | int64_t mtime; |
47 | int32_t version; |
48 | int32_t cversion; |
49 | int32_t aversion; |
50 | int64_t ephemeralOwner; |
51 | int32_t dataLength; |
52 | int32_t numChildren; |
53 | int64_t pzxid; |
54 | }; |
55 | |
56 | struct Request; |
57 | using RequestPtr = std::shared_ptr<Request>; |
58 | using Requests = std::vector<RequestPtr>; |
59 | |
60 | struct Request |
61 | { |
62 | Request() = default; |
63 | Request(const Request &) = default; |
64 | Request & operator=(const Request &) = default; |
65 | virtual ~Request() = default; |
66 | virtual String getPath() const = 0; |
67 | virtual void addRootPath(const String & /* root_path */) {} |
68 | }; |
69 | |
70 | struct Response; |
71 | using ResponsePtr = std::shared_ptr<Response>; |
72 | using Responses = std::vector<ResponsePtr>; |
73 | using ResponseCallback = std::function<void(const Response &)>; |
74 | |
75 | struct Response |
76 | { |
77 | int32_t error = 0; |
78 | Response() = default; |
79 | Response(const Response &) = default; |
80 | Response & operator=(const Response &) = default; |
81 | virtual ~Response() = default; |
82 | virtual void removeRootPath(const String & /* root_path */) {} |
83 | }; |
84 | |
85 | struct WatchResponse : virtual Response |
86 | { |
87 | int32_t type = 0; |
88 | int32_t state = 0; |
89 | String path; |
90 | |
91 | void removeRootPath(const String & root_path) override; |
92 | }; |
93 | |
94 | using WatchCallback = std::function<void(const WatchResponse &)>; |
95 | |
96 | struct CreateRequest : virtual Request |
97 | { |
98 | String path; |
99 | String data; |
100 | bool is_ephemeral = false; |
101 | bool is_sequential = false; |
102 | ACLs acls; |
103 | |
104 | void addRootPath(const String & root_path) override; |
105 | String getPath() const override { return path; } |
106 | }; |
107 | |
108 | struct CreateResponse : virtual Response |
109 | { |
110 | String path_created; |
111 | |
112 | void removeRootPath(const String & root_path) override; |
113 | }; |
114 | |
115 | struct RemoveRequest : virtual Request |
116 | { |
117 | String path; |
118 | int32_t version = -1; |
119 | |
120 | void addRootPath(const String & root_path) override; |
121 | String getPath() const override { return path; } |
122 | }; |
123 | |
124 | struct RemoveResponse : virtual Response |
125 | { |
126 | }; |
127 | |
128 | struct ExistsRequest : virtual Request |
129 | { |
130 | String path; |
131 | |
132 | void addRootPath(const String & root_path) override; |
133 | String getPath() const override { return path; } |
134 | }; |
135 | |
136 | struct ExistsResponse : virtual Response |
137 | { |
138 | Stat stat; |
139 | }; |
140 | |
141 | struct GetRequest : virtual Request |
142 | { |
143 | String path; |
144 | |
145 | void addRootPath(const String & root_path) override; |
146 | String getPath() const override { return path; } |
147 | }; |
148 | |
149 | struct GetResponse : virtual Response |
150 | { |
151 | String data; |
152 | Stat stat; |
153 | }; |
154 | |
155 | struct SetRequest : virtual Request |
156 | { |
157 | String path; |
158 | String data; |
159 | int32_t version = -1; |
160 | |
161 | void addRootPath(const String & root_path) override; |
162 | String getPath() const override { return path; } |
163 | }; |
164 | |
165 | struct SetResponse : virtual Response |
166 | { |
167 | Stat stat; |
168 | }; |
169 | |
170 | struct ListRequest : virtual Request |
171 | { |
172 | String path; |
173 | |
174 | void addRootPath(const String & root_path) override; |
175 | String getPath() const override { return path; } |
176 | }; |
177 | |
178 | struct ListResponse : virtual Response |
179 | { |
180 | std::vector<String> names; |
181 | Stat stat; |
182 | }; |
183 | |
184 | struct CheckRequest : virtual Request |
185 | { |
186 | String path; |
187 | int32_t version = -1; |
188 | |
189 | void addRootPath(const String & root_path) override; |
190 | String getPath() const override { return path; } |
191 | }; |
192 | |
193 | struct CheckResponse : virtual Response |
194 | { |
195 | }; |
196 | |
197 | struct MultiRequest : virtual Request |
198 | { |
199 | Requests requests; |
200 | |
201 | void addRootPath(const String & root_path) override; |
202 | String getPath() const override { return {}; } |
203 | }; |
204 | |
205 | struct MultiResponse : virtual Response |
206 | { |
207 | Responses responses; |
208 | |
209 | void removeRootPath(const String & root_path) override; |
210 | }; |
211 | |
212 | /// This response may be received only as an element of responses in MultiResponse. |
213 | struct ErrorResponse : virtual Response |
214 | { |
215 | }; |
216 | |
217 | |
218 | using CreateCallback = std::function<void(const CreateResponse &)>; |
219 | using RemoveCallback = std::function<void(const RemoveResponse &)>; |
220 | using ExistsCallback = std::function<void(const ExistsResponse &)>; |
221 | using GetCallback = std::function<void(const GetResponse &)>; |
222 | using SetCallback = std::function<void(const SetResponse &)>; |
223 | using ListCallback = std::function<void(const ListResponse &)>; |
224 | using CheckCallback = std::function<void(const CheckResponse &)>; |
225 | using MultiCallback = std::function<void(const MultiResponse &)>; |
226 | |
227 | |
228 | enum Error |
229 | { |
230 | ZOK = 0, |
231 | |
232 | /** System and server-side errors. |
233 | * This is never thrown by the server, it shouldn't be used other than |
234 | * to indicate a range. Specifically error codes greater than this |
235 | * value, but lesser than ZAPIERROR, are system errors. |
236 | */ |
237 | ZSYSTEMERROR = -1, |
238 | |
239 | ZRUNTIMEINCONSISTENCY = -2, /// A runtime inconsistency was found |
240 | ZDATAINCONSISTENCY = -3, /// A data inconsistency was found |
241 | ZCONNECTIONLOSS = -4, /// Connection to the server has been lost |
242 | ZMARSHALLINGERROR = -5, /// Error while marshalling or unmarshalling data |
243 | ZUNIMPLEMENTED = -6, /// Operation is unimplemented |
244 | ZOPERATIONTIMEOUT = -7, /// Operation timeout |
245 | ZBADARGUMENTS = -8, /// Invalid arguments |
246 | ZINVALIDSTATE = -9, /// Invliad zhandle state |
247 | |
248 | /** API errors. |
249 | * This is never thrown by the server, it shouldn't be used other than |
250 | * to indicate a range. Specifically error codes greater than this |
251 | * value are API errors. |
252 | */ |
253 | ZAPIERROR = -100, |
254 | |
255 | ZNONODE = -101, /// Node does not exist |
256 | ZNOAUTH = -102, /// Not authenticated |
257 | ZBADVERSION = -103, /// Version conflict |
258 | ZNOCHILDRENFOREPHEMERALS = -108, /// Ephemeral nodes may not have children |
259 | ZNODEEXISTS = -110, /// The node already exists |
260 | ZNOTEMPTY = -111, /// The node has children |
261 | ZSESSIONEXPIRED = -112, /// The session has been expired by the server |
262 | ZINVALIDCALLBACK = -113, /// Invalid callback specified |
263 | ZINVALIDACL = -114, /// Invalid ACL specified |
264 | ZAUTHFAILED = -115, /// Client authentication failed |
265 | ZCLOSING = -116, /// ZooKeeper is closing |
266 | ZNOTHING = -117, /// (not error) no server responses to process |
267 | ZSESSIONMOVED = -118 /// Session moved to another server, so operation is ignored |
268 | }; |
269 | |
270 | /// Network errors and similar. You should reinitialize ZooKeeper session in case of these errors |
271 | bool isHardwareError(int32_t code); |
272 | |
273 | /// Valid errors sent from the server about database state (like "no node"). Logical and authentication errors (like "bad arguments") are not here. |
274 | bool isUserError(int32_t code); |
275 | |
276 | const char * errorMessage(int32_t code); |
277 | |
278 | /// For watches. |
279 | enum State |
280 | { |
281 | EXPIRED_SESSION = -112, |
282 | AUTH_FAILED = -113, |
283 | CONNECTING = 1, |
284 | ASSOCIATING = 2, |
285 | CONNECTED = 3, |
286 | NOTCONNECTED = 999 |
287 | }; |
288 | |
289 | enum Event |
290 | { |
291 | CREATED = 1, |
292 | DELETED = 2, |
293 | CHANGED = 3, |
294 | CHILD = 4, |
295 | SESSION = -1, |
296 | NOTWATCHING = -2 |
297 | }; |
298 | |
299 | |
300 | class Exception : public DB::Exception |
301 | { |
302 | private: |
303 | /// Delegate constructor, used to minimize repetition; last parameter used for overload resolution. |
304 | Exception(const std::string & msg, const int32_t code_, int); |
305 | |
306 | public: |
307 | explicit Exception(const int32_t code_); |
308 | Exception(const std::string & msg, const int32_t code_); |
309 | Exception(const int32_t code_, const std::string & path); |
310 | Exception(const Exception & exc); |
311 | |
312 | const char * name() const throw() override { return "Coordination::Exception" ; } |
313 | const char * className() const throw() override { return "Coordination::Exception" ; } |
314 | Exception * clone() const override { return new Exception(*this); } |
315 | |
316 | const int32_t code; |
317 | }; |
318 | |
319 | |
320 | /** Usage scenario: |
321 | * - create an object and issue commands; |
322 | * - you provide callbacks for your commands; callbacks are invoked in internal thread and must be cheap: |
323 | * for example, just signal a condvar / fulfull a promise. |
324 | * - you also may provide callbacks for watches; they are also invoked in internal thread and must be cheap. |
325 | * - whenever you receive exception with ZSESSIONEXPIRED code or method isExpired returns true, |
326 | * the ZooKeeper instance is no longer usable - you may only destroy it and probably create another. |
327 | * - whenever session is expired or ZooKeeper instance is destroying, all callbacks are notified with special event. |
328 | * - data for callbacks must be alive when ZooKeeper instance is alive. |
329 | */ |
330 | class IKeeper |
331 | { |
332 | public: |
333 | virtual ~IKeeper() {} |
334 | |
335 | /// If expired, you can only destroy the object. All other methods will throw exception. |
336 | virtual bool isExpired() const = 0; |
337 | |
338 | /// Useful to check owner of ephemeral node. |
339 | virtual int64_t getSessionID() const = 0; |
340 | |
341 | /// If the method will throw an exception, callbacks won't be called. |
342 | /// |
343 | /// After the method is executed successfully, you must wait for callbacks |
344 | /// (don't destroy callback data before it will be called). |
345 | /// |
346 | /// All callbacks are executed sequentially (the execution of callbacks is serialized). |
347 | /// |
348 | /// If an exception is thrown inside the callback, the session will expire, |
349 | /// and all other callbacks will be called with "Session expired" error. |
350 | |
351 | virtual void create( |
352 | const String & path, |
353 | const String & data, |
354 | bool is_ephemeral, |
355 | bool is_sequential, |
356 | const ACLs & acls, |
357 | CreateCallback callback) = 0; |
358 | |
359 | virtual void remove( |
360 | const String & path, |
361 | int32_t version, |
362 | RemoveCallback callback) = 0; |
363 | |
364 | virtual void exists( |
365 | const String & path, |
366 | ExistsCallback callback, |
367 | WatchCallback watch) = 0; |
368 | |
369 | virtual void get( |
370 | const String & path, |
371 | GetCallback callback, |
372 | WatchCallback watch) = 0; |
373 | |
374 | virtual void set( |
375 | const String & path, |
376 | const String & data, |
377 | int32_t version, |
378 | SetCallback callback) = 0; |
379 | |
380 | virtual void list( |
381 | const String & path, |
382 | ListCallback callback, |
383 | WatchCallback watch) = 0; |
384 | |
385 | virtual void check( |
386 | const String & path, |
387 | int32_t version, |
388 | CheckCallback callback) = 0; |
389 | |
390 | virtual void multi( |
391 | const Requests & requests, |
392 | MultiCallback callback) = 0; |
393 | }; |
394 | |
395 | } |
396 | |