1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * Copyright 2017 Couchbase, Inc
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "collections/collections_dockey.h"
21 #include "collections/collections_types.h"
22 #include "collections/manifest.h"
23 #include "collections/vbucket_manifest_entry.h"
24 #include "systemevent.h"
26 #include <platform/sized_buffer.h>
27 #include <platform/rwlock.h>
30 #include <unordered_map>
34 namespace Collections {
38 * Collections::VB::Manifest is a container for all of the collections a VBucket
41 * Each collection is represented by a Collections::VB::ManifestEntry and all of
42 * the collections are stored in an unordered_map. The map is implemented to
43 * allow look-up by collection-name without having to allocate a std::string,
44 * callers only need a cb::const_char_buffer for look-ups.
46 * The Manifest allows for an external manager to drive the lifetime of each
47 * collection - adding, begin/complete of the deletion phase.
49 * This class is intended to be thread-safe when accessed through the read
50 * or write handles (providing RAII locking).
52 * Access to the class is peformed by the ReadHandle and WriteHandle classes
53 * which perform RAII locking on the manifest's internal lock. A user of the
54 * manifest is required to hold the correct handle for the required scope to
55 * to ensure any actions they take based upon a collection's existence are
56 * consistent. The important consistency issue is the checkpoint. For example
57 * when setting a document code must first check the document's collection
58 * exists, the document must then only enter the checkpoint after the creation
59 * event for the collection and also before a delete event foe the collection.
60 * Thus the set path must obtain read access to collections and keep read access
61 * for the entire scope of the set path to ensure no other thread can interleave
62 * collection create/delete and cause an inconsistency in the checkpoint
68 * RAII read locking for access to the Manifest.
72 ReadHandle(const Manifest& m, cb::RWLock& lock)
73 : readLock(lock), manifest(m) {
76 ReadHandle(ReadHandle&& rhs)
77 : readLock(std::move(rhs.readLock)), manifest(rhs.manifest) {
81 * Does the key contain a valid collection?
83 * - If the key applies to the default collection, the default
84 * collection must exist.
86 * - If the key applies to a collection, the collection must exist and
87 * must not be in the process of deletion.
89 bool doesKeyContainValidCollection(::DocKey key) {
90 return manifest.doesKeyContainValidCollection(key);
94 * @returns a copy of the current separator
96 std::string getSeparator() const {
97 return manifest.getSeparator();
101 * @returns true/false if $default exists
103 bool doesDefaultCollectionExist() const {
104 return manifest.doesDefaultCollectionExist();
108 * @returns true/false if the collection exists
110 bool doesCollectionExist(cb::const_char_buffer collection) const {
111 return manifest.doesCollectionExist(collection);
115 std::unique_lock<cb::ReaderLock> readLock;
116 const Manifest& manifest;
120 * RAII write locking for access and updates to the Manifest.
124 WriteHandle(Manifest& m, cb::RWLock& lock)
125 : writeLock(lock), manifest(m) {
128 WriteHandle(WriteHandle&& rhs)
129 : writeLock(std::move(rhs.writeLock)), manifest(rhs.manifest) {
133 * Update from a Collections::Manifest
135 * Update compares the current collection set against the manifest and
136 * triggers collection creation and collection deletion.
138 * Creation and deletion of a collection are pushed into the VBucket and
139 * the seqno of updates is recorded in the manifest.
141 * @param vb The VBucket to update (queue data into).
142 * @param manifest The incoming manifest to compare this object with.
144 void update(::VBucket& vb, const Collections::Manifest& newManifest) {
145 manifest.update(vb, newManifest);
149 * Complete the deletion of a collection.
151 * Lookup the collection name and determine the deletion actions.
152 * A collection could of been added again during a background delete so
153 * completeDeletion may just update the state or fully drop all
154 * knowledge of the collection.
156 * @param vb The VBucket in which the deletion is occuring.
157 * @param collection The collection that is being deleted.
158 * @param revision The Manifest revision which initiated the delete.
160 void completeDeletion(::VBucket& vb,
161 cb::const_char_buffer collection,
163 manifest.completeDeletion(vb, collection, revision);
167 * Add a collection for a replica VB, this is for receiving
168 * collection updates via DCP and the collection already has a start
171 * @param vb The vbucket to add the collection to.
172 * @param collection Name of the new collection.
173 * @param revision Manifest revision which added the collection.
174 * @param startSeqno The start-seqno assigned to the collection.
176 void replicaAdd(::VBucket& vb,
177 cb::const_char_buffer collection,
179 int64_t startSeqno) {
180 manifest.addCollection(
181 vb, collection, revision, OptionalSeqno{startSeqno});
185 * Begin a delete collection for a replica VB, this is for receiving
186 * collection updates via DCP and the collection already has an end
189 * @param vb The vbucket to begin collection deletion on.
190 * @param collection Name of the deleted collection.
191 * @param revision manifest revision which started the deletion.
192 * @param endSeqno The end-seqno assigned to the end collection.
194 void replicaBeginDelete(::VBucket& vb,
195 cb::const_char_buffer collection,
198 manifest.beginCollectionDelete(
199 vb, collection, revision, OptionalSeqno{endSeqno});
203 * Change the separator for a replica VB, this is for receiving
204 * collection updates via DCP and the event already has an end seqno
207 * @param vb The vbucket to begin collection deletion on.
208 * @param separator The new separator.
209 * @param revision manifest revision which changed the separator.
210 * @param seqno The seqno orginally assigned to the active's system
213 void replicaChangeSeparator(::VBucket& vb,
214 cb::const_char_buffer separator,
217 manifest.changeSeparator(
218 vb, separator, revision, OptionalSeqno{seqno});
222 std::unique_lock<cb::WriterLock> writeLock;
230 * Map from a 'string_view' to an entry.
231 * The key points to data stored in the value (which is actually a pointer
232 * to a value to remove issues where objects move).
233 * Using the string_view as the key allows faster lookups, the caller
234 * need not heap allocate.
236 using container = ::std::unordered_map<cb::const_char_buffer,
237 std::unique_ptr<ManifestEntry>>;
240 * Construct a VBucket::Manifest from a JSON string or an empty string.
242 * Empty string allows for construction where no JSON data was found i.e.
243 * an upgrade occurred and this is the first construction of a manifest
244 * for a VBucket which has persisted data, but no manifest data. When an
245 * empty string is used, the manifest will initialise with default settings.
246 * - Default Collection enabled.
247 * - Separator defined as Collections::DefaultSeparator
249 * A non-empty string must be a valid JSON manifest that determines which
250 * collections to instantiate.
252 * @param manifest A std::string containing a JSON manifest. An empty string
253 * indicates no manifest and is valid.
255 Manifest(const std::string& manifest);
257 ReadHandle lock() const {
258 return {*this, rwlock};
261 WriteHandle wlock() {
262 return {*this, rwlock};
266 * Return a std::string containing a JSON representation of a
267 * VBucket::Manifest. The input data should be a previously serialised
268 * object, i.e. the input to this function is the output of
269 * populateWithSerialisedData.
271 * The function also corrects the seqno of the entry which initiated a
272 * manifest update (i.e. a collection create or delete). This is because at
273 * the time of serialisation, the collection SystemEvent Item did not have a
276 * @param se The SystemEvent triggering the JSON generation.
277 * @param buffer The raw data to process.
278 * @param finalEntrySeqno The correct seqno to use for the final entry of
279 * the serialised data.
281 static std::string serialToJson(SystemEvent se,
282 cb::const_char_buffer buffer,
283 int64_t finalEntrySeqno);
286 * Get the system event data from a SystemEvent, that is the information
287 * that DCP would require to send a SystemEvent to a client.
289 * @param serialisedManifest Serialised manifest data created by
290 * ::populateWithSerialisedData
291 * @returns a pair of buffers. The first buffer contains a pointer to
292 * the collection name, the second buffer contains the revision.
293 * Both buffers are pointing to data inside of the input param.
295 static std::pair<cb::const_char_buffer, cb::const_byte_buffer>
296 getSystemEventData(cb::const_char_buffer serialisedManifest);
299 * Get the system event data from a SystemEvent, that is the information
300 * that DCP would require to send a SystemEvent to a client.
302 * This particular function returns separator changed data.
304 * @param serialisedManifest Serialised manifest data created by
305 * ::populateWithSerialisedData
306 * @returns a pair of buffers. The first buffer contains a pointer to
307 * the separator, the second buffer contains the revision.
308 * Both buffers are pointing to data inside of the input param.
310 static std::pair<cb::const_char_buffer, cb::const_byte_buffer>
311 getSystemEventSeparatorData(cb::const_char_buffer serialisedManifest);
316 * Return a std::string containing a JSON representation of a
317 * VBucket::Manifest. The input data should be a previously serialised
318 * object, i.e. the input to this function is the output of
319 * populateWithSerialisedData(cb::char_buffer out)
321 * @param buffer The raw data to process.
322 * @returns std::string containing a JSON representation of the manifest
324 static std::string serialToJson(cb::const_char_buffer buffer);
327 * Update from a Collections::Manifest
329 * Update compares the current collection set against the manifest and
330 * triggers collection creation and collection deletion.
332 * Creation and deletion of a collection are pushed into the VBucket and
333 * the seqno of updates is recorded in the manifest.
335 * @param vb The VBucket to update (queue data into).
336 * @param manifest The incoming manifest to compare this object with.
338 void update(::VBucket& vb, const Collections::Manifest& manifest);
341 * Add a collection to the manifest.
343 * @param vb The vbucket to add the collection to.
344 * @param collection Name of the new collection.
345 * @param revision manifest revision which added the collection.
346 * @param optionalSeqno Either a seqno to assign to the new collection or
347 * none (none means the checkpoint will assign a seqno).
349 void addCollection(::VBucket& vb,
350 cb::const_char_buffer collection,
352 OptionalSeqno optionalSeqno);
355 * Begin a delete of the collection.
357 * @param vb The vbucket to begin collection deletion on.
358 * @param collection Name of the deleted collection.
359 * @param revision manifest revision which started the deletion.
360 * @param optionalSeqno Either a seqno to assign to the delete of the
361 * collection or none (none means the checkpoint assigns the seqno).
363 void beginCollectionDelete(::VBucket& vb,
364 cb::const_char_buffer collection,
366 OptionalSeqno optionalSeqno);
369 * Change the separator.
371 * @param vb The vbucket to begin collection deletion on.
372 * @param separator The new separator.
373 * @param revision manifest revision which changed the separator.
374 * @param optionalSeqno Either a seqno to assign to the change event or none
375 * (none means the checkpoint assigns the seqno).
377 void changeSeparator(::VBucket& vb,
378 cb::const_char_buffer separator,
380 OptionalSeqno optionalSeqno);
383 * Complete the deletion of a collection.
385 * Lookup the collection name and determine the deletion actions.
386 * A collection could of been added again during a background delete so
387 * completeDeletion may just update the state or fully drop all knowledge of
390 * @param vb The VBucket in which the deletion is occuring.
391 * @param collection The collection that is being deleted.
392 * @param revision The Manifest revision which initiated the delete.
394 void completeDeletion(::VBucket& vb,
395 cb::const_char_buffer collection,
399 * Does the key contain a valid collection?
401 * - If the key applies to the default collection, the default collection
404 * - If the key applies to a collection, the collection must exist and must
405 * not be in the process of deletion.
407 bool doesKeyContainValidCollection(const ::DocKey& key) const;
410 * @returns the current separator
412 std::string getSeparator() const {
418 * @returns true/false if $default exists
420 bool doesDefaultCollectionExist() const {
421 return defaultCollectionExists;
425 * @returns true/false if the collection exists
427 bool doesCollectionExist(cb::const_char_buffer collection) const {
428 return map.count(collection) != 0;
433 * Add a collection entry to the manifest specifing the revision that it was
434 * seen in and the sequence number for the point in 'time' it was created.
436 * @param collection Name of the collection to add.
437 * @param revision The revision of the Collections::Manifest triggering this
439 * @param startSeqno The seqno of an Item which represents the creation
443 void addCollectionEntry(cb::const_char_buffer collection,
449 * Begin the deletion process by marking the collection entry with the seqno
450 * that represents its end.
452 * After "begin" delete a collection can be added again or fully deleted
453 * by the completeDeletion method.
455 * @param collection Name of the collection to delete.
456 * @param revision Revision of the Manifest triggering the delete.
457 * @param seqno The seqno of the deleted event mutation for the collection
460 void beginDeleteCollectionEntry(cb::const_char_buffer collection,
465 * Processs a Collections::Manifest
467 * This function returns two sets of collections. Those which are being
468 * added and those which are being deleted.
470 * @param manifest The Manifest to compare with.
471 * @returns A pair of vector containing the required changes, first contains
472 * collections that need adding whilst second contains those which
475 using processResult =
476 std::pair<std::vector<std::string>, std::vector<std::string>>;
477 processResult processManifest(const Collections::Manifest& manifest) const;
480 * Create a SystemEvent Item, the Item's value will contain data for later
481 * consumption by serialToJson
483 * @param se SystemEvent to create.
484 * @param collection The collection which is changing,
485 * @param revision Manifest revision triggering the update, this value will
486 * be used for the JSON manifest update (as part of flushing).
487 * @param seqno An optional sequence number. If a seqno is specified, the
488 * returned item will have its bySeqno set to seqno.
490 * @returns unique_ptr to a new Item that represents the requested
493 std::unique_ptr<Item> createSystemEvent(SystemEvent se,
494 cb::const_char_buffer collection,
496 OptionalSeqno seqno) const;
499 * Create a SystemEvent Item for a Separator Changed. The Item's
500 * value will contain data for later consumption by serialToJson.
502 * @param separator The new separator
503 * @param revision The revision of the manifest triggering the change.
505 * @returns unique_ptr to a new Item that represents the requested
508 std::unique_ptr<Item> createSeparatorChangedEvent(
509 uint32_t revision, OptionalSeqno seqno) const;
512 * Create an Item that carries a system event and queue it to the vb
515 * @param vb The vbucket onto which the Item is queued.
516 * @param se The SystemEvent to create and queue.
517 * @param collection The name of the collection being added/deleted
518 * @param revision The revision of the manifest which triggered the update.
519 * @param seqno An optional seqno which if set will be assigned to the
522 * @returns The sequence number of the queued Item.
524 int64_t queueSystemEvent(::VBucket& vb,
526 cb::const_char_buffer collection,
528 OptionalSeqno seqno) const;
531 * Create an Item that carries a CollectionsSeparatorChanged system event
532 * and queue it to the vb checkpoint.
534 * @param vb The vbucket onto which the Item is queued.
535 * @param revision The revision id of the manifest which changed the
538 int64_t queueSeparatorChanged(::VBucket& vb,
540 OptionalSeqno seqno) const;
543 * Obtain how many bytes of storage are needed for a serialised copy
544 * of this object including the size of the modified collection.
546 * @param collection The name of the collection being changed. It's size is
547 * included in the returned value.
548 * @returns how many bytes will be needed to serialise the manifest and
549 * the collection being changed.
551 size_t getSerialisedDataSize(cb::const_char_buffer collection) const;
554 * Obtain how many bytes of storage are needed for a serialised copy
557 * @returns how many bytes will be needed to serialise the manifest.
559 size_t getSerialisedDataSize() const;
562 * Populate a buffer with the serialised state of the manifest and one
563 * additional entry that is the collection being changed, i.e. the addition
566 * @param out A buffer for the data to be written into.
567 * @param revision The Manifest revision we are processing
568 * @param collection The collection being added/deleted
570 void populateWithSerialisedData(cb::char_buffer out,
571 cb::const_char_buffer collection,
572 uint32_t revision) const;
575 * Populate a buffer with the serialised state of this object.
577 * @param out A buffer for the data to be written into.
578 * @param revision The Manifest revision we are processing
580 void populateWithSerialisedData(cb::char_buffer out,
581 uint32_t revision) const;
584 * @returns the string for the given key from the cJSON object.
586 const char* getJsonEntry(cJSON* cJson, const char* key);
589 * @returns true if the separator cannot be changed.
591 bool cannotChangeSeparator() const;
594 * The current set of collections
599 * Does the current set contain the default collection?
601 bool defaultCollectionExists;
604 * The collection separator
606 std::string separator;
609 * shared lock to allow concurrent readers and safe updates
611 mutable cb::RWLock rwlock;
613 friend std::ostream& operator<<(std::ostream& os, const Manifest& manifest);
616 /// Note that the VB::Manifest << operator does not obtain the rwlock
617 /// it is used internally in the object for exception string generation so must
619 std::ostream& operator<<(std::ostream& os, const Manifest& manifest);
621 } // end namespace VB
622 } // end namespace Collections