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 #pragma once
19 
20 #include "collections/collections_types.h"
21 #include "stored-value.h"
22 #include "systemevent.h"
23 
24 #include <platform/make_unique.h>
25 #include <platform/sized_buffer.h>
26 
27 #include <memory>
28 
29 namespace Collections {
30 namespace VB {
31 
32 /**
33  * The Collections::VB::ManifestEntry stores the data a collection
34  * needs from a vbucket's perspective.
35  * - The Collections::Manifest revision
36  * - The seqno lifespace of the collection
37  *
38  * Additionally this object is designed for use by Collections::VB::Manifest,
39  * this is why the object stores a pointer to a std::string collection name,
40  * rather than including the entire object std::string.
41  * Thus a std::map can map from cb::const_char_buffer, ManifestEntry, where
42  * the buffer refers to the key we own via the pointer.
43  */
44 class ManifestEntry {
45 public:
ManifestEntry(Identifier identifier, int64_t _startSeqno, int64_t _endSeqno)46     ManifestEntry(Identifier identifier, int64_t _startSeqno, int64_t _endSeqno)
47         : collectionName(std::make_unique<std::string>(
48                   identifier.getName().data(), identifier.getName().size())),
49           uid(identifier.getUid()),
50           startSeqno(-1),
51           endSeqno(-1) {
52         // Setters validate the start/end range is valid
53         setStartSeqno(_startSeqno);
54         setEndSeqno(_endSeqno);
55     }
56 
ManifestEntry(const ManifestEntry& rhs)57     ManifestEntry(const ManifestEntry& rhs)
58         : collectionName(
59                   std::make_unique<std::string>(rhs.collectionName->c_str())),
60           uid(rhs.uid),
61           startSeqno(rhs.startSeqno),
62           endSeqno(rhs.endSeqno) {
63     }
64 
ManifestEntry(ManifestEntry&& rhs)65     ManifestEntry(ManifestEntry&& rhs)
66         : collectionName(std::move(rhs.collectionName)),
67           uid(rhs.uid),
68           startSeqno(rhs.startSeqno),
69           endSeqno(rhs.endSeqno) {
70     }
71 
operator =(ManifestEntry&& rhs)72     ManifestEntry& operator=(ManifestEntry&& rhs) {
73         std::swap(collectionName, rhs.collectionName);
74         uid = rhs.uid;
75         startSeqno = rhs.startSeqno;
76         endSeqno = rhs.endSeqno;
77         return *this;
78     }
79 
operator =(const ManifestEntry& rhs)80     ManifestEntry& operator=(const ManifestEntry& rhs) {
81         collectionName.reset(new std::string(rhs.collectionName->c_str()));
82         uid = rhs.uid;
83         startSeqno = rhs.startSeqno;
84         endSeqno = rhs.endSeqno;
85         return *this;
86     }
87 
getCollectionName() const88     const std::string& getCollectionName() const {
89         return *collectionName;
90     }
91 
92     /**
93      * @return const_char_buffer initialised with address/size of the internal
94      *         collection-name string data.
95      */
getCharBuffer() const96     cb::const_char_buffer getCharBuffer() const {
97         return cb::const_char_buffer(collectionName->data(),
98                                      collectionName->size());
99     }
100 
getIdentifier() const101     Identifier getIdentifier() const {
102         return {getCharBuffer(), getUid()};
103     }
104 
getStartSeqno() const105     int64_t getStartSeqno() const {
106         return startSeqno;
107     }
108 
setStartSeqno(int64_t seqno)109     void setStartSeqno(int64_t seqno) {
110         // Enforcing that start/end are not the same, they should always be
111         // separated because they represent start/end mutations.
112         if (seqno < 0 || seqno <= startSeqno || seqno == endSeqno) {
113             throwException<std::invalid_argument>(
114                     __FUNCTION__,
115                     "cannot set startSeqno to " + std::to_string(seqno));
116         }
117         startSeqno = seqno;
118     }
119 
getEndSeqno() const120     int64_t getEndSeqno() const {
121         return endSeqno;
122     }
123 
setEndSeqno(int64_t seqno)124     void setEndSeqno(int64_t seqno) {
125         // Enforcing that start/end are not the same, they should always be
126         // separated because they represent start/end mutations.
127         if (seqno != StoredValue::state_collection_open &&
128             (seqno <= endSeqno || seqno == startSeqno)) {
129             throwException<std::invalid_argument>(
130                     __FUNCTION__,
131                     "cannot set "
132                     "endSeqno to " +
133                             std::to_string(seqno));
134         }
135         endSeqno = seqno;
136     }
137 
resetEndSeqno()138     void resetEndSeqno() {
139         endSeqno = StoredValue::state_collection_open;
140     }
141 
getUid() const142     uid_t getUid() const {
143         return uid;
144     }
145 
setUid(uid_t uid)146     void setUid(uid_t uid) {
147         this->uid = uid;
148     }
149 
150     /**
151      * A collection is open when the start is greater than the end.
152      * An open collection is one that is readable and writable by the data
153      * path.
154      */
isOpen() const155     bool isOpen() const {
156         return startSeqno > endSeqno;
157     }
158 
159     /**
160      * A collection is being deleted when the endSeqno is not the special
161      * state_collection_open value.
162      */
isDeleting() const163     bool isDeleting() const {
164         return endSeqno != StoredValue::state_collection_open;
165     }
166 
167     /**
168      * A collection can be open whilst at the same time a previous incarnation
169      * of it is being deleted.
170      * isOpenAndDeleted returns true for exactly this case
171      */
isOpenAndDeleting() const172     bool isOpenAndDeleting() const {
173         return isOpen() && isDeleting();
174     }
175 
176     /**
177      * A collection can be open whilst at the same time a previous incarnation
178      * of it is being deleted.
179      * Exclusively Open is true only when there is no deletion in progress.
180      */
isExclusiveOpen() const181     bool isExclusiveOpen() const {
182         return isOpen() && !isDeleting();
183     }
184 
185     /**
186      * A collection can be open whilst at the same time a previous incarnation
187      * of it is being deleted.
188      * Exclusively Deleting means that there was no re-addition of the
189      * collection, it is only deleting.
190      */
isExclusiveDeleting() const191     bool isExclusiveDeleting() const {
192         return !isOpen() && isDeleting();
193     }
194 
195     /**
196      * Inform the collection that all items of the collection up to endSeqno
197      * have been deleted.
198      *
199      * @return the correct SystemEvent for vbucket manifest management. If the
200      *         collection has been reopened, a soft delete, else hard.
201      */
202     SystemEvent completeDeletion();
203 
204 private:
205     /**
206      * Return a string for use in throwException, returns:
207      *   "VB::ManifestEntry::<thrower>:<error>, this:<ostream *this>"
208      *
209      * @param thrower a string for who is throwing, typically __FUNCTION__
210      * @param error a string containing the error and useful data
211      * @returns string as per description above
212      */
213     std::string getExceptionString(const std::string& thrower,
214                                    const std::string& error) const;
215 
216     /**
217      * throw exception with the following error string:
218      *   "VB::ManifestEntry::<thrower>:<error>, this:<ostream *this>"
219      *
220      * @param thrower a string for who is throwing, typically __FUNCTION__
221      * @param error a string containing the error and useful data
222      * @throws exception
223      */
224     template <class exception>
throwException(const std::string& thrower, const std::string& error) const225     [[noreturn]] void throwException(const std::string& thrower,
226                                      const std::string& error) const {
227         throw exception(getExceptionString(thrower, error));
228     }
229 
230     /**
231      * An entry has a name that is heap allocated... this is due to the
232      * way ManifestEntry objects are stored in the VB::Manifest
233      */
234     std::unique_ptr<std::string> collectionName;
235 
236     /**
237      * The uid of the collection
238      */
239     uid_t uid;
240 
241     /**
242      * Collection life-time is recorded as the seqno the collection was added
243      * to the seqno of the point we started to delete it.
244      *
245      * If a collection is not being deleted then endSeqno has a value of
246      * StoredValue::state_collection_open to indicate this.
247      */
248     int64_t startSeqno;
249     int64_t endSeqno;
250 };
251 
252 std::ostream& operator<<(std::ostream& os, const ManifestEntry& manifestEntry);
253 
254 } // end namespace VB
255 } // end namespace Collections