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