1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include "config.h"
19#include "nobucket.h"
20
21#include <cstdlib>
22#include <stdexcept>
23#include <string>
24
25/**
26 * The NoBucket is a bucket that just returns "ENGINE_NO_BUCKET" for "all"
27 * operations. The main purpose for having this bucket is to reduce the
28 * code complexity so we don't have to had checks all over the place to
29 * see if a client is connected to a bucket or not (we may just associate
30 * the connection to this bucket and it'll handle the appropriate
31 * command.
32 */
33class NoBucket : public ENGINE_HANDLE_V1 {
34public:
35    NoBucket() {
36        memset(this, 0, sizeof(*this));
37        ENGINE_HANDLE_V1::interface.interface = 1;
38        ENGINE_HANDLE_V1::initialize = initialize;
39        ENGINE_HANDLE_V1::destroy = destroy;
40        ENGINE_HANDLE_V1::allocate = item_allocate;
41        ENGINE_HANDLE_V1::allocate_ex = item_allocate_ex;
42        ENGINE_HANDLE_V1::remove = item_delete;
43        ENGINE_HANDLE_V1::release = item_release;
44        ENGINE_HANDLE_V1::get = get;
45        ENGINE_HANDLE_V1::get_meta = get_meta;
46        ENGINE_HANDLE_V1::get_if = get_if;
47        ENGINE_HANDLE_V1::get_and_touch = get_and_touch;
48        ENGINE_HANDLE_V1::get_locked = get_locked;
49        ENGINE_HANDLE_V1::unlock = unlock;
50        ENGINE_HANDLE_V1::get_stats = get_stats;
51        ENGINE_HANDLE_V1::reset_stats = reset_stats;
52        ENGINE_HANDLE_V1::store = store;
53        ENGINE_HANDLE_V1::store_if = store_if;
54        ENGINE_HANDLE_V1::flush = flush;
55        ENGINE_HANDLE_V1::unknown_command = unknown_command;
56        ENGINE_HANDLE_V1::item_set_cas = item_set_cas;
57        ENGINE_HANDLE_V1::item_set_datatype = item_set_datatype;
58        ENGINE_HANDLE_V1::get_item_info = get_item_info;
59        ENGINE_HANDLE_V1::set_item_info = set_item_info;
60        ENGINE_HANDLE_V1::dcp.step = dcp_step;
61        ENGINE_HANDLE_V1::dcp.open = dcp_open;
62        ENGINE_HANDLE_V1::dcp.add_stream = dcp_add_stream;
63        ENGINE_HANDLE_V1::dcp.close_stream = dcp_close_stream;
64        ENGINE_HANDLE_V1::dcp.get_failover_log = dcp_get_failover_log;
65        ENGINE_HANDLE_V1::dcp.stream_req = dcp_stream_req;
66        ENGINE_HANDLE_V1::dcp.stream_end = dcp_stream_end;
67        ENGINE_HANDLE_V1::dcp.snapshot_marker = dcp_snapshot_marker;
68        ENGINE_HANDLE_V1::dcp.mutation = dcp_mutation;
69        ENGINE_HANDLE_V1::dcp.deletion = dcp_deletion;
70        ENGINE_HANDLE_V1::dcp.deletion_v2 = dcp_deletion_v2;
71        ENGINE_HANDLE_V1::dcp.expiration = dcp_expiration;
72        ENGINE_HANDLE_V1::dcp.flush = dcp_flush;
73        ENGINE_HANDLE_V1::dcp.set_vbucket_state = dcp_set_vbucket_state;
74        ENGINE_HANDLE_V1::dcp.system_event = dcp_system_event;
75        ENGINE_HANDLE_V1::collections.set_manifest = collections_set_manifest;
76        ENGINE_HANDLE_V1::collections.get_manifest = collections_get_manifest;
77        ENGINE_HANDLE_V1::isXattrEnabled = isXattrEnabled;
78        ENGINE_HANDLE_V1::getMaxItemSize = getMaxItemSize;
79    };
80
81private:
82    /**
83     * Convert the ENGINE_HANDLE to the underlying class type
84     *
85     * @param handle the handle as provided by the frontend
86     * @return the actual no bucket object
87     */
88    static NoBucket* get_handle(ENGINE_HANDLE* handle) {
89        return reinterpret_cast<NoBucket*>(handle);
90    }
91
92    static ENGINE_ERROR_CODE initialize(gsl::not_null<ENGINE_HANDLE*>,
93                                        const char*) {
94        return ENGINE_SUCCESS;
95    }
96
97    static void destroy(gsl::not_null<ENGINE_HANDLE*> handle, const bool) {
98        delete get_handle(handle);
99    }
100
101    static cb::EngineErrorItemPair item_allocate(gsl::not_null<ENGINE_HANDLE*>,
102                                                 gsl::not_null<const void*>,
103                                                 const DocKey&,
104                                                 const size_t,
105                                                 const int,
106                                                 const rel_time_t,
107                                                 uint8_t,
108                                                 uint16_t) {
109        return cb::makeEngineErrorItemPair(cb::engine_errc::no_bucket);
110    }
111
112    static std::pair<cb::unique_item_ptr, item_info> item_allocate_ex(
113            gsl::not_null<ENGINE_HANDLE*>,
114            gsl::not_null<const void*> cookie,
115            const DocKey&,
116            size_t,
117            size_t,
118            int,
119            rel_time_t,
120            uint8_t,
121            uint16_t) {
122        throw cb::engine_error(cb::engine_errc::no_bucket, "no bucket");
123    }
124
125    static ENGINE_ERROR_CODE item_delete(gsl::not_null<ENGINE_HANDLE*>,
126                                         gsl::not_null<const void*>,
127                                         const DocKey&,
128                                         uint64_t&,
129                                         uint16_t,
130                                         mutation_descr_t&) {
131        return ENGINE_NO_BUCKET;
132    }
133
134    static void item_release(gsl::not_null<ENGINE_HANDLE*>,
135                             gsl::not_null<item*>) {
136        throw std::logic_error("NoBucket::item_release: no items should have"
137                                   " been allocated from this engine");
138    }
139
140    static cb::EngineErrorItemPair get(gsl::not_null<ENGINE_HANDLE*> h,
141                                       gsl::not_null<const void*>,
142                                       const DocKey&,
143                                       uint16_t,
144                                       DocStateFilter) {
145        return cb::makeEngineErrorItemPair(cb::engine_errc::no_bucket);
146    }
147
148    static cb::EngineErrorMetadataPair get_meta(
149            gsl::not_null<ENGINE_HANDLE*> handle,
150            gsl::not_null<const void*> cookie,
151            const DocKey& key,
152            uint16_t vbucket) {
153        return cb::EngineErrorMetadataPair(cb::engine_errc::no_bucket, {});
154    }
155
156    static cb::EngineErrorItemPair get_if(
157            gsl::not_null<ENGINE_HANDLE*> handle,
158            gsl::not_null<const void*>,
159            const DocKey&,
160            uint16_t,
161            std::function<bool(const item_info&)>) {
162        return cb::makeEngineErrorItemPair(cb::engine_errc::no_bucket);
163    }
164
165    static cb::EngineErrorItemPair get_and_touch(
166            gsl::not_null<ENGINE_HANDLE*> handle,
167            gsl::not_null<const void*> cookie,
168            const DocKey&,
169            uint16_t,
170            uint32_t) {
171        return cb::makeEngineErrorItemPair(cb::engine_errc::no_bucket);
172    }
173
174    static cb::EngineErrorItemPair get_locked(gsl::not_null<ENGINE_HANDLE*>,
175                                              gsl::not_null<const void*>,
176                                              const DocKey&,
177                                              uint16_t,
178                                              uint32_t) {
179        return cb::makeEngineErrorItemPair(cb::engine_errc::no_bucket);
180    }
181
182    static ENGINE_ERROR_CODE unlock(gsl::not_null<ENGINE_HANDLE*>,
183                                    gsl::not_null<const void*>,
184                                    const DocKey&,
185                                    uint16_t,
186                                    uint64_t) {
187        return ENGINE_NO_BUCKET;
188    }
189
190    static ENGINE_ERROR_CODE get_stats(gsl::not_null<ENGINE_HANDLE*>,
191                                       gsl::not_null<const void*>,
192                                       cb::const_char_buffer key,
193                                       ADD_STAT) {
194        return ENGINE_NO_BUCKET;
195    }
196
197    static ENGINE_ERROR_CODE store(gsl::not_null<ENGINE_HANDLE*>,
198                                   gsl::not_null<const void*>,
199                                   gsl::not_null<item*>,
200                                   uint64_t&,
201                                   ENGINE_STORE_OPERATION,
202                                   DocumentState) {
203        return ENGINE_NO_BUCKET;
204    }
205
206    static cb::EngineErrorCasPair store_if(gsl::not_null<ENGINE_HANDLE*>,
207                                           gsl::not_null<const void*>,
208                                           gsl::not_null<item*>,
209                                           uint64_t,
210                                           ENGINE_STORE_OPERATION,
211                                           cb::StoreIfPredicate,
212                                           DocumentState) {
213        return {cb::engine_errc::no_bucket, 0};
214    }
215
216    static ENGINE_ERROR_CODE flush(gsl::not_null<ENGINE_HANDLE*>,
217                                   gsl::not_null<const void*>) {
218        return ENGINE_NO_BUCKET;
219    }
220
221    static void reset_stats(gsl::not_null<ENGINE_HANDLE*>, gsl::not_null<const void*> cookie) {
222    }
223
224    static ENGINE_ERROR_CODE unknown_command(
225            gsl::not_null<ENGINE_HANDLE*>,
226            const void*,
227            gsl::not_null<protocol_binary_request_header*>,
228            ADD_RESPONSE,
229            DocNamespace) {
230        return ENGINE_NO_BUCKET;
231    }
232
233    static void item_set_cas(gsl::not_null<ENGINE_HANDLE*>,
234                             gsl::not_null<item*>,
235                             uint64_t) {
236        throw std::logic_error("NoBucket::item_set_cas: no items should have"
237                                   " been allocated from this engine");
238    }
239
240    static void item_set_datatype(gsl::not_null<ENGINE_HANDLE*>,
241                                  gsl::not_null<item*>,
242                                  protocol_binary_datatype_t) {
243        throw std::logic_error(
244                "NoBucket::item_set_datatype: no items should have"
245                " been allocated from this engine");
246    }
247
248    static bool get_item_info(gsl::not_null<ENGINE_HANDLE*>,
249                              gsl::not_null<const item*>,
250                              gsl::not_null<item_info*>) {
251        throw std::logic_error("NoBucket::get_item_info: no items should have"
252                                   " been allocated from this engine");
253    }
254
255    static bool set_item_info(gsl::not_null<ENGINE_HANDLE*>,
256                              gsl::not_null<item*>,
257                              gsl::not_null<const item_info*>) {
258        throw std::logic_error("NoBucket::set_item_info: no items should have"
259                                   " been allocated from this engine");
260    }
261
262    static ENGINE_ERROR_CODE dcp_step(
263            gsl::not_null<ENGINE_HANDLE*>,
264            gsl::not_null<const void*>,
265            gsl::not_null<struct dcp_message_producers*>) {
266        return ENGINE_NO_BUCKET;
267    }
268
269    static ENGINE_ERROR_CODE dcp_open(gsl::not_null<ENGINE_HANDLE*>,
270                                      gsl::not_null<const void*>,
271                                      uint32_t,
272                                      uint32_t,
273                                      uint32_t,
274                                      cb::const_char_buffer,
275                                      cb::const_byte_buffer) {
276        return ENGINE_NO_BUCKET;
277    }
278
279    static ENGINE_ERROR_CODE dcp_add_stream(gsl::not_null<ENGINE_HANDLE*>,
280                                            gsl::not_null<const void*>,
281                                            uint32_t,
282                                            uint16_t,
283                                            uint32_t) {
284        return ENGINE_NO_BUCKET;
285    }
286
287    static ENGINE_ERROR_CODE dcp_close_stream(gsl::not_null<ENGINE_HANDLE*>,
288                                              gsl::not_null<const void*>,
289                                              uint32_t,
290                                              uint16_t) {
291        return ENGINE_NO_BUCKET;
292    }
293
294    static ENGINE_ERROR_CODE dcp_stream_req(gsl::not_null<ENGINE_HANDLE*>,
295                                            gsl::not_null<const void*>,
296                                            uint32_t,
297                                            uint32_t,
298                                            uint16_t,
299                                            uint64_t,
300                                            uint64_t,
301                                            uint64_t,
302                                            uint64_t,
303                                            uint64_t,
304                                            uint64_t*,
305                                            dcp_add_failover_log) {
306        return ENGINE_NO_BUCKET;
307    }
308
309    static ENGINE_ERROR_CODE dcp_get_failover_log(
310            gsl::not_null<ENGINE_HANDLE*>,
311            gsl::not_null<const void*>,
312            uint32_t,
313            uint16_t,
314            ENGINE_ERROR_CODE (*)(vbucket_failover_t*,
315                                  size_t,
316                                  gsl::not_null<const void*>)) {
317        return ENGINE_NO_BUCKET;
318    }
319
320    static ENGINE_ERROR_CODE dcp_stream_end(gsl::not_null<ENGINE_HANDLE*>,
321                                            gsl::not_null<const void*>,
322                                            uint32_t,
323                                            uint16_t,
324                                            uint32_t) {
325        return ENGINE_NO_BUCKET;
326    }
327
328    static ENGINE_ERROR_CODE dcp_snapshot_marker(gsl::not_null<ENGINE_HANDLE*>,
329                                                 gsl::not_null<const void*>,
330                                                 uint32_t,
331                                                 uint16_t,
332                                                 uint64_t,
333                                                 uint64_t,
334                                                 uint32_t) {
335        return ENGINE_NO_BUCKET;
336    }
337
338    static ENGINE_ERROR_CODE dcp_mutation(gsl::not_null<ENGINE_HANDLE*>,
339                                          gsl::not_null<const void*>,
340                                          uint32_t,
341                                          const DocKey&,
342                                          cb::const_byte_buffer,
343                                          size_t,
344                                          uint8_t,
345                                          uint64_t,
346                                          uint16_t,
347                                          uint32_t,
348                                          uint64_t,
349                                          uint64_t,
350                                          uint32_t,
351                                          uint32_t,
352                                          cb::const_byte_buffer,
353                                          uint8_t) {
354        return ENGINE_NO_BUCKET;
355    }
356
357    static ENGINE_ERROR_CODE dcp_deletion(gsl::not_null<ENGINE_HANDLE*>,
358                                          gsl::not_null<const void*>,
359                                          uint32_t,
360                                          const DocKey&,
361                                          cb::const_byte_buffer,
362                                          size_t,
363                                          uint8_t,
364                                          uint64_t,
365                                          uint16_t,
366                                          uint64_t,
367                                          uint64_t,
368                                          cb::const_byte_buffer) {
369        return ENGINE_NO_BUCKET;
370    }
371
372    static ENGINE_ERROR_CODE dcp_deletion_v2(gsl::not_null<ENGINE_HANDLE*>,
373                                             gsl::not_null<const void*>,
374                                             uint32_t,
375                                             const DocKey&,
376                                             cb::const_byte_buffer,
377                                             size_t,
378                                             uint8_t,
379                                             uint64_t,
380                                             uint16_t,
381                                             uint64_t,
382                                             uint64_t,
383                                             uint32_t) {
384        return ENGINE_NO_BUCKET;
385    }
386
387    static ENGINE_ERROR_CODE dcp_expiration(gsl::not_null<ENGINE_HANDLE*>,
388                                            gsl::not_null<const void*>,
389                                            uint32_t,
390                                            const DocKey&,
391                                            cb::const_byte_buffer,
392                                            size_t,
393                                            uint8_t,
394                                            uint64_t,
395                                            uint16_t,
396                                            uint64_t,
397                                            uint64_t,
398                                            cb::const_byte_buffer) {
399        return ENGINE_NO_BUCKET;
400    }
401
402    static ENGINE_ERROR_CODE dcp_flush(gsl::not_null<ENGINE_HANDLE*>,
403                                       gsl::not_null<const void*>,
404                                       uint32_t,
405                                       uint16_t) {
406        return ENGINE_NO_BUCKET;
407    }
408
409    static ENGINE_ERROR_CODE dcp_set_vbucket_state(
410            gsl::not_null<ENGINE_HANDLE*>,
411            gsl::not_null<const void*>,
412            uint32_t,
413            uint16_t,
414            vbucket_state_t) {
415        return ENGINE_NO_BUCKET;
416    }
417
418    static ENGINE_ERROR_CODE dcp_system_event(
419            gsl::not_null<ENGINE_HANDLE*> handle,
420            gsl::not_null<const void*> cookie,
421            uint32_t opaque,
422            uint16_t vbucket,
423            mcbp::systemevent::id event,
424            uint64_t bySeqno,
425            cb::const_byte_buffer key,
426            cb::const_byte_buffer eventData) {
427        return ENGINE_NO_BUCKET;
428    }
429
430    static cb::engine_error collections_set_manifest(
431            gsl::not_null<ENGINE_HANDLE*> handle, cb::const_char_buffer json) {
432        return {cb::engine_errc::no_bucket,
433                "nobucket::collections_set_manifest"};
434    }
435
436    static cb::EngineErrorStringPair collections_get_manifest(
437            gsl::not_null<ENGINE_HANDLE*> handle) {
438        return {cb::engine_errc::no_bucket,
439                "nobucket::collections_get_manifest"};
440    }
441
442    static bool isXattrEnabled(gsl::not_null<ENGINE_HANDLE*> handle) {
443        return false;
444    }
445
446    static BucketCompressionMode getCompressionMode(gsl::not_null<ENGINE_HANDLE*> handle) {
447        return BucketCompressionMode::Off;
448    }
449
450    static size_t getMaxItemSize(gsl::not_null<ENGINE_HANDLE*> handle) {
451        return default_max_item_size;
452    }
453
454    static float getMinCompressionRatio(gsl::not_null<ENGINE_HANDLE*> handle) {
455        return default_min_compression_ratio;
456    }
457};
458
459MEMCACHED_PUBLIC_API
460ENGINE_ERROR_CODE create_no_bucket_instance(uint64_t interface,
461                                            GET_SERVER_API get_server_api,
462                                            ENGINE_HANDLE **handle)
463{
464    if (interface != 1) {
465        return ENGINE_ENOTSUP;
466    }
467
468    try {
469        NoBucket* engine = new NoBucket();
470        *handle = reinterpret_cast<ENGINE_HANDLE*>(engine);
471    } catch (std::bad_alloc& e) {
472        auto logger = get_server_api()->log->get_logger();
473        logger->log(EXTENSION_LOG_WARNING, NULL,
474                    "NoBucket: failed to create engine: %s", e.what());
475        return ENGINE_FAILED;
476    }
477
478    return ENGINE_SUCCESS;
479}
480
481MEMCACHED_PUBLIC_API
482void destroy_engine(void) {
483    // Empty
484}
485