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
18 #include "collections/manager.h"
19 #include "collections/filter.h"
20 #include "collections/manifest.h"
21 #include "ep_engine.h"
22 #include "kv_bucket.h"
23 #include "vbucket.h"
24
Manager()25 Collections::Manager::Manager() {
26 }
27
update(KVBucket& bucket, const std::string& json)28 cb::engine_error Collections::Manager::update(KVBucket& bucket,
29 const std::string& json) {
30 std::unique_lock<std::mutex> ul(lock, std::try_to_lock);
31 if (!ul.owns_lock()) {
32 // Make concurrent updates fail, in realiy there should only be one
33 // admin connection making changes.
34 return cb::engine_error(cb::engine_errc::temporary_failure,
35 "Collections::Manager::update already locked");
36 }
37
38 std::unique_ptr<Manifest> newManifest;
39 // Construct a newManifest (will throw if JSON was illegal)
40 try {
41 newManifest =
42 std::make_unique<Manifest>(json,
43 bucket.getEPEngine()
44 .getConfiguration()
45 .getCollectionsMaxSize());
46 } catch (std::exception& e) {
47 LOG(EXTENSION_LOG_NOTICE,
48 "Collections::Manager::update can't construct manifest e.what:%s",
49 e.what());
50 return cb::engine_error(
51 cb::engine_errc::invalid_arguments,
52 "Collections::Manager::update manifest json invalid:" + json);
53 }
54
55 current = std::move(newManifest);
56
57 for (int i = 0; i < bucket.getVBuckets().getSize(); i++) {
58 auto vb = bucket.getVBuckets().getBucket(i);
59
60 if (vb && vb->getState() == vbucket_state_active) {
61 vb->updateFromManifest(*current);
62 }
63 }
64
65 return cb::engine_error(cb::engine_errc::success,
66 "Collections::Manager::update");
67 }
68
getManifest() const69 cb::EngineErrorStringPair Collections::Manager::getManifest() const {
70 std::unique_lock<std::mutex> ul(lock);
71 if (current) {
72 return {cb::engine_errc::success, current->toJson()};
73 } else {
74 return {cb::engine_errc::no_collections_manifest, {}};
75 }
76 }
77
update(VBucket& vb) const78 void Collections::Manager::update(VBucket& vb) const {
79 // Lock manager updates
80 std::lock_guard<std::mutex> ul(lock);
81 if (current) {
82 vb.updateFromManifest(*current);
83 }
84 }
85
makeFilter( uint32_t openFlags, cb::const_byte_buffer jsonExtra) const86 Collections::Filter Collections::Manager::makeFilter(
87 uint32_t openFlags, cb::const_byte_buffer jsonExtra) const {
88 // Lock manager updates
89 std::lock_guard<std::mutex> lg(lock);
90 boost::optional<const std::string&> jsonFilter;
91 std::string json;
92 if (openFlags & DCP_OPEN_COLLECTIONS) {
93 // assign to std::string as cJSON needs guaranteed zero termination
94 json.assign(reinterpret_cast<const char*>(jsonExtra.data()),
95 jsonExtra.size());
96 jsonFilter = json;
97 }
98 return Collections::Filter(jsonFilter, current.get());
99 }
100
101 // This method is really to aid development and allow the dumping of the VB
102 // collection data to the logs.
logAll(KVBucket& bucket) const103 void Collections::Manager::logAll(KVBucket& bucket) const {
104 std::stringstream ss;
105 ss << *this;
106 LOG(EXTENSION_LOG_NOTICE, "%s", ss.str().c_str());
107 for (int i = 0; i < bucket.getVBuckets().getSize(); i++) {
108 auto vb = bucket.getVBuckets().getBucket(i);
109 if (vb) {
110 std::stringstream vbss;
111 vbss << vb->lockCollections();
112 LOG(EXTENSION_LOG_NOTICE,
113 "vb:%d: %s %s",
114 i,
115 VBucket::toString(vb->getState()),
116 vbss.str().c_str());
117 }
118 }
119 }
120
dump() const121 void Collections::Manager::dump() const {
122 std::cerr << *this;
123 }
124
operator <<(std::ostream& os, const Collections::Manager& manager)125 std::ostream& Collections::operator<<(std::ostream& os,
126 const Collections::Manager& manager) {
127 std::lock_guard<std::mutex> lg(manager.lock);
128 if (manager.current) {
129 os << "Collections::Manager current:" << *manager.current << "\n";
130 } else {
131 os << "Collections::Manager current:nullptr\n";
132 }
133 return os;
134 }
135