1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2017 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 #include "create_remove_bucket_command_context.h"
18 
19 #include <daemon/enginemap.h>
20 #include <daemon/executorpool.h>
21 #include <daemon/mcbp.h>
22 #include <daemon/mcbpdestroybuckettask.h>
23 
24 /**
25  * Override the CreateBucketTask so that we can have our own notification
26  * mechanism to kickstart the clients thread
27  */
28 class McbpCreateBucketTask : public Task {
29 public:
McbpCreateBucketTask(const std::string& name_, const std::string& config_, const BucketType& type_, Cookie& cookie_)30     McbpCreateBucketTask(const std::string& name_,
31                          const std::string& config_,
32                          const BucketType& type_,
33                          Cookie& cookie_)
34         : thread(name_, config_, type_, cookie_.getConnection(), this),
35           cookie(cookie_) {
36     }
37 
38     // start the bucket deletion
39     // May throw std::bad_alloc if we're failing to start the thread
start()40     void start() {
41         thread.start();
42     }
43 
44     Status execute() override {
45         return Status::Finished;
46     }
47 
48     void notifyExecutionComplete() override {
49         notify_io_complete(static_cast<const void*>(&cookie),
50                            thread.getResult());
51     }
52 
53     CreateBucketThread thread;
54     Cookie& cookie;
55 };
56 
initial()57 ENGINE_ERROR_CODE CreateRemoveBucketCommandContext::initial() {
58     if (request.getClientOpcode() == cb::mcbp::ClientOpcode::CreateBucket) {
59         state = State::Create;
60     } else {
61         state = State::Remove;
62     }
63 
64     return ENGINE_SUCCESS;
65 }
66 
create()67 ENGINE_ERROR_CODE CreateRemoveBucketCommandContext::create() {
68     auto k = request.getKey();
69     auto v = request.getValue();
70 
71     std::string name(reinterpret_cast<const char*>(k.data()), k.size());
72     std::string value(reinterpret_cast<const char*>(v.data()), v.size());
73     std::string config;
74 
75     // Check if (optional) config was included after the value.
76     auto marker = value.find('\0');
77     if (marker != std::string::npos) {
78         config.assign(&value[marker + 1]);
79     }
80 
81     std::string errors;
82     BucketType type = module_to_bucket_type(value.c_str());
83     task = std::make_shared<McbpCreateBucketTask>(name, config, type, cookie);
84     std::lock_guard<std::mutex> guard(task->getMutex());
85     reinterpret_cast<McbpCreateBucketTask*>(task.get())->start();
86     executorPool->schedule(task, false);
87 
88     state = State::Done;
89     return ENGINE_EWOULDBLOCK;
90 }
91 
remove()92 ENGINE_ERROR_CODE CreateRemoveBucketCommandContext::remove() {
93     auto k = request.getKey();
94     auto v = request.getValue();
95 
96     std::string name(reinterpret_cast<const char*>(k.data()), k.size());
97     std::string config(reinterpret_cast<const char*>(v.data()), v.size());
98     bool force = false;
99 
100     std::vector<struct config_item> items(2);
101     items[0].key = "force";
102     items[0].datatype = DT_BOOL;
103     items[0].value.dt_bool = &force;
104     items[1].key = NULL;
105 
106     if (parse_config(config.c_str(), items.data(), stderr) != 0) {
107         return ENGINE_EINVAL;
108     }
109 
110     task = std::make_shared<McbpDestroyBucketTask>(name, force, &cookie);
111     std::lock_guard<std::mutex> guard(task->getMutex());
112     reinterpret_cast<McbpDestroyBucketTask*>(task.get())->start();
113     executorPool->schedule(task, false);
114 
115     state = State::Done;
116     return ENGINE_EWOULDBLOCK;
117 }
118 
step()119 ENGINE_ERROR_CODE CreateRemoveBucketCommandContext::step() {
120     try {
121         auto ret = ENGINE_SUCCESS;
122         do {
123             switch (state) {
124             case State::Initial:
125                 ret = initial();
126                 break;
127             case State::Create:
128                 ret = create();
129                 break;
130             case State::Remove:
131                 ret = remove();
132                 break;
133             case State::Done:
134                 cookie.sendResponse(cb::mcbp::Status::Success);
135                 return ENGINE_SUCCESS;
136             }
137         } while (ret == ENGINE_SUCCESS);
138 
139         return ret;
140     } catch (const std::bad_alloc&) {
141         return ENGINE_ENOMEM;
142     }
143 }
144