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