fc830ccc6d345e25cc9f0beaa8813c7097862843
[ep-engine.git] / src / collections / vbucket_manifest.h
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_dockey.h"
21 #include "collections/collections_types.h"
22 #include "collections/manifest.h"
23 #include "collections/vbucket_manifest_entry.h"
24 #include "systemevent.h"
25
26 #include <platform/sized_buffer.h>
27 #include <platform/rwlock.h>
28
29 #include <mutex>
30 #include <unordered_map>
31
32 class VBucket;
33
34 namespace Collections {
35 namespace VB {
36
37 /**
38  * Collections::VB::Manifest is a container for all of the collections a VBucket
39  * knows about.
40  *
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.
45  *
46  * The Manifest allows for an external manager to drive the lifetime of each
47  * collection - adding, begin/complete of the deletion phase.
48  *
49  * This class is intended to be thread-safe when accessed through the read
50  * or write handles (providing RAII locking).
51  *
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
63  * ordering.
64  */
65 class Manifest {
66 public:
67     /**
68      * RAII read locking for access to the Manifest.
69      */
70     class ReadHandle {
71     public:
72         ReadHandle(const Manifest& m, cb::RWLock& lock)
73             : readLock(lock), manifest(m) {
74         }
75
76         ReadHandle(ReadHandle&& rhs)
77             : readLock(std::move(rhs.readLock)), manifest(rhs.manifest) {
78         }
79
80         /**
81          * Does the key contain a valid collection?
82          *
83          * - If the key applies to the default collection, the default
84          *   collection must exist.
85          *
86          * - If the key applies to a collection, the collection must exist and
87          *   must not be in the process of deletion.
88          */
89         bool doesKeyContainValidCollection(::DocKey key) {
90             return manifest.doesKeyContainValidCollection(key);
91         }
92
93         /**
94          * @returns a copy of the current separator
95          */
96         std::string getSeparator() const {
97             return manifest.getSeparator();
98         }
99
100         /**
101          * @returns true/false if $default exists
102          */
103         bool doesDefaultCollectionExist() const {
104             return manifest.doesDefaultCollectionExist();
105         }
106
107         /**
108          * @returns true/false if the collection exists
109          */
110         bool doesCollectionExist(cb::const_char_buffer collection) const {
111             return manifest.doesCollectionExist(collection);
112         }
113
114     private:
115         std::unique_lock<cb::ReaderLock> readLock;
116         const Manifest& manifest;
117     };
118
119     /**
120      * RAII write locking for access and updates to the Manifest.
121      */
122     class WriteHandle {
123     public:
124         WriteHandle(Manifest& m, cb::RWLock& lock)
125             : writeLock(lock), manifest(m) {
126         }
127
128         WriteHandle(WriteHandle&& rhs)
129             : writeLock(std::move(rhs.writeLock)), manifest(rhs.manifest) {
130         }
131
132         /**
133          * Update from a Collections::Manifest
134          *
135          * Update compares the current collection set against the manifest and
136          * triggers collection creation and collection deletion.
137          *
138          * Creation and deletion of a collection are pushed into the VBucket and
139          * the seqno of updates is recorded in the manifest.
140          *
141          * @param vb The VBucket to update (queue data into).
142          * @param manifest The incoming manifest to compare this object with.
143          */
144         void update(::VBucket& vb, const Collections::Manifest& newManifest) {
145             manifest.update(vb, newManifest);
146         }
147
148         /**
149          * Complete the deletion of a collection.
150          *
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.
155          *
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.
159          */
160         void completeDeletion(::VBucket& vb,
161                               cb::const_char_buffer collection,
162                               uint32_t revision) {
163             manifest.completeDeletion(vb, collection, revision);
164         }
165
166         /**
167          * Add a collection for a replica VB, this is for receiving
168          * collection updates via DCP and the collection already has a start
169          * seqno assigned.
170          *
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.
175          */
176         void replicaAdd(::VBucket& vb,
177                         cb::const_char_buffer collection,
178                         uint32_t revision,
179                         int64_t startSeqno) {
180             manifest.addCollection(
181                     vb, collection, revision, OptionalSeqno{startSeqno});
182         }
183
184         /**
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
187          * seqno assigned.
188          *
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.
193          */
194         void replicaBeginDelete(::VBucket& vb,
195                                 cb::const_char_buffer collection,
196                                 uint32_t revision,
197                                 int64_t endSeqno) {
198             manifest.beginCollectionDelete(
199                     vb, collection, revision, OptionalSeqno{endSeqno});
200         }
201
202         /**
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
205          * assigned.
206          *
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
211          * event.
212          */
213         void replicaChangeSeparator(::VBucket& vb,
214                                     cb::const_char_buffer separator,
215                                     uint32_t revision,
216                                     int64_t seqno) {
217             manifest.changeSeparator(
218                     vb, separator, revision, OptionalSeqno{seqno});
219         }
220
221     private:
222         std::unique_lock<cb::WriterLock> writeLock;
223         Manifest& manifest;
224     };
225
226     friend ReadHandle;
227     friend WriteHandle;
228
229     /**
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.
235      */
236     using container = ::std::unordered_map<cb::const_char_buffer,
237                                            std::unique_ptr<ManifestEntry>>;
238
239     /**
240      * Construct a VBucket::Manifest from a JSON string or an empty string.
241      *
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
248      *
249      * A non-empty string must be a valid JSON manifest that determines which
250      * collections to instantiate.
251      *
252      * @param manifest A std::string containing a JSON manifest. An empty string
253      *        indicates no manifest and is valid.
254      */
255     Manifest(const std::string& manifest);
256
257     ReadHandle lock() const {
258         return {*this, rwlock};
259     }
260
261     WriteHandle wlock() {
262         return {*this, rwlock};
263     }
264
265     /**
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.
270      *
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
274      * seqno.
275      *
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.
280      */
281     static std::string serialToJson(SystemEvent se,
282                                     cb::const_char_buffer buffer,
283                                     int64_t finalEntrySeqno);
284
285     /**
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.
288      *
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.
294      */
295     static std::pair<cb::const_char_buffer, cb::const_byte_buffer>
296     getSystemEventData(cb::const_char_buffer serialisedManifest);
297
298     /**
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.
301      *
302      * This particular function returns separator changed data.
303      *
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.
309      */
310     static std::pair<cb::const_char_buffer, cb::const_byte_buffer>
311     getSystemEventSeparatorData(cb::const_char_buffer serialisedManifest);
312
313 private:
314
315     /**
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)
320      *
321      * @param buffer The raw data to process.
322      * @returns std::string containing a JSON representation of the manifest
323      */
324     static std::string serialToJson(cb::const_char_buffer buffer);
325
326     /**
327      * Update from a Collections::Manifest
328      *
329      * Update compares the current collection set against the manifest and
330      * triggers collection creation and collection deletion.
331      *
332      * Creation and deletion of a collection are pushed into the VBucket and
333      * the seqno of updates is recorded in the manifest.
334      *
335      * @param vb The VBucket to update (queue data into).
336      * @param manifest The incoming manifest to compare this object with.
337      */
338     void update(::VBucket& vb, const Collections::Manifest& manifest);
339
340     /**
341      * Add a collection to the manifest.
342      *
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).
348      */
349     void addCollection(::VBucket& vb,
350                        cb::const_char_buffer collection,
351                        uint32_t revision,
352                        OptionalSeqno optionalSeqno);
353
354     /**
355      * Begin a delete of the collection.
356      *
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).
362      */
363     void beginCollectionDelete(::VBucket& vb,
364                                cb::const_char_buffer collection,
365                                uint32_t revision,
366                                OptionalSeqno optionalSeqno);
367
368     /**
369      * Change the separator.
370      *
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).
376      */
377     void changeSeparator(::VBucket& vb,
378                          cb::const_char_buffer separator,
379                          uint32_t revision,
380                          OptionalSeqno optionalSeqno);
381
382     /**
383      * Complete the deletion of a collection.
384      *
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
388      * the collection.
389      *
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.
393      */
394     void completeDeletion(::VBucket& vb,
395                           cb::const_char_buffer collection,
396                           uint32_t revision);
397
398     /**
399      * Does the key contain a valid collection?
400      *
401      * - If the key applies to the default collection, the default collection
402      *   must exist.
403      *
404      * - If the key applies to a collection, the collection must exist and must
405      *   not be in the process of deletion.
406      */
407     bool doesKeyContainValidCollection(const ::DocKey& key) const;
408
409     /**
410      * @returns the current separator
411      */
412     std::string getSeparator() const {
413         return separator;
414     }
415
416
417     /**
418      * @returns true/false if $default exists
419      */
420     bool doesDefaultCollectionExist() const {
421         return defaultCollectionExists;
422     }
423
424     /**
425      * @returns true/false if the collection exists
426      */
427     bool doesCollectionExist(cb::const_char_buffer collection) const {
428         return map.count(collection) != 0;
429     }
430
431 protected:
432     /**
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.
435      *
436      * @param collection Name of the collection to add.
437      * @param revision The revision of the Collections::Manifest triggering this
438      *        add.
439      * @param startSeqno The seqno of an Item which represents the creation
440      *        event.
441      * @param endSeqno
442      */
443     void addCollectionEntry(cb::const_char_buffer collection,
444                             uint32_t revision,
445                             int64_t startSeqno,
446                             int64_t endSeqno);
447
448     /**
449      * Begin the deletion process by marking the collection entry with the seqno
450      * that represents its end.
451      *
452      * After "begin" delete a collection can be added again or fully deleted
453      * by the completeDeletion method.
454      *
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
458      *        deletion,
459      */
460     void beginDeleteCollectionEntry(cb::const_char_buffer collection,
461                                     uint32_t revision,
462                                     int64_t seqno);
463
464     /**
465      * Processs a Collections::Manifest
466      *
467      * This function returns two sets of collections. Those which are being
468      * added and those which are being deleted.
469      *
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
473      *          should be deleted.
474      */
475     using processResult =
476             std::pair<std::vector<std::string>, std::vector<std::string>>;
477     processResult processManifest(const Collections::Manifest& manifest) const;
478
479     /**
480      * Create a SystemEvent Item, the Item's value will contain data for later
481      * consumption by serialToJson
482      *
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.
489      *
490      * @returns unique_ptr to a new Item that represents the requested
491      *          SystemEvent.
492      */
493     std::unique_ptr<Item> createSystemEvent(SystemEvent se,
494                                             cb::const_char_buffer collection,
495                                             uint32_t revision,
496                                             OptionalSeqno seqno) const;
497
498     /**
499      * Create a SystemEvent Item for a Separator Changed. The Item's
500      * value will contain data for later consumption by serialToJson.
501      *
502      * @param separator The new separator
503      * @param revision The revision of the manifest triggering the change.
504      *
505      * @returns unique_ptr to a new Item that represents the requested
506      *          SystemEvent.
507      */
508     std::unique_ptr<Item> createSeparatorChangedEvent(
509             uint32_t revision, OptionalSeqno seqno) const;
510
511     /**
512      * Create an Item that carries a system event and queue it to the vb
513      * checkpoint.
514      *
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
520      *        system event
521      *
522      * @returns The sequence number of the queued Item.
523      */
524     int64_t queueSystemEvent(::VBucket& vb,
525                              SystemEvent se,
526                              cb::const_char_buffer collection,
527                              uint32_t revision,
528                              OptionalSeqno seqno) const;
529
530     /**
531      * Create an Item that carries a CollectionsSeparatorChanged system event
532      * and queue it to the vb checkpoint.
533      *
534      * @param vb The vbucket onto which the Item is queued.
535      * @param revision The revision id of the manifest which changed the
536      *        separator.
537      */
538     int64_t queueSeparatorChanged(::VBucket& vb,
539                                   uint32_t revision,
540                                   OptionalSeqno seqno) const;
541
542     /**
543      * Obtain how many bytes of storage are needed for a serialised copy
544      * of this object including the size of the modified collection.
545      *
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.
550      */
551     size_t getSerialisedDataSize(cb::const_char_buffer collection) const;
552
553     /**
554      * Obtain how many bytes of storage are needed for a serialised copy
555      * of this object.
556      *
557      * @returns how many bytes will be needed to serialise the manifest.
558      */
559     size_t getSerialisedDataSize() const;
560
561     /**
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
564      * or deletion.
565      *
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
569      */
570     void populateWithSerialisedData(cb::char_buffer out,
571                                     cb::const_char_buffer collection,
572                                     uint32_t revision) const;
573
574     /**
575      * Populate a buffer with the serialised state of this object.
576      *
577      * @param out A buffer for the data to be written into.
578      * @param revision The Manifest revision we are processing
579      */
580     void populateWithSerialisedData(cb::char_buffer out,
581                                     uint32_t revision) const;
582
583     /**
584      * @returns the string for the given key from the cJSON object.
585      */
586     const char* getJsonEntry(cJSON* cJson, const char* key);
587
588     /**
589      * @returns true if the separator cannot be changed.
590      */
591     bool cannotChangeSeparator() const;
592
593     /**
594      * The current set of collections
595      */
596     container map;
597
598     /**
599      * Does the current set contain the default collection?
600      */
601     bool defaultCollectionExists;
602
603     /**
604      * The collection separator
605      */
606     std::string separator;
607
608     /**
609      * shared lock to allow concurrent readers and safe updates
610      */
611     mutable cb::RWLock rwlock;
612
613     friend std::ostream& operator<<(std::ostream& os, const Manifest& manifest);
614 };
615
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
618 /// not double lock.
619 std::ostream& operator<<(std::ostream& os, const Manifest& manifest);
620
621 } // end namespace VB
622 } // end namespace Collections