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 <memcached/dockey.h>
21
22#include "atomic.h"
23#include "ep_types.h"
24
25#include <string>
26
27class Item;
28class KVStore;
29class SystemEventMessage;
30
31/// underlying size of uint32_t as this is to be stored in the Item flags field.
32enum class SystemEvent : uint32_t {
33    /**
34     * The Collection system event represents the beginning or end of a
35     * collection. Each Collection system event has a key which contains the
36     * collection name. When the event is queued in a checkpoint or stored on
37     * disk the seqno of that item states that this is the point when that
38     * collection became accessible unless that queued/stored item is deleted,
39     * then it represent when that collection became inaccesible (logically
40     * deleted).
41     *
42     * A Collection system event when queued into a checkpoint carries with it
43     * a value, the value is used to maintain a per vbucket JSON collection's
44     * manifest (for persisted buckets).
45     */
46    Collection,
47
48    /**
49     * The DeleteCollectionHard system event is generated when a VBucket has
50     * completed the deletion of all items of a collection. The hard delete
51     * carries data to the flusher so we can persist a JSON manifest that now
52     * fully removes the collection and also deleted the special marker document
53     * created by CreateCollection.
54     */
55    DeleteCollectionHard,
56
57    /**
58     * The DeleteCollectionSoft system event is generated when a VBucket has
59     * completed the deletion of all items of a collection *but*  a
60     * collection of the same name was added back during the deletion. The soft
61     * delete carries data to the flusher so we can persist a JSON manifest that
62     * only updates the end-seqno of the deleted collection entry. The soft
63     * delete also deleted the special marker document created by
64     * CreateCollection.
65     */
66    DeleteCollectionSoft,
67
68    /**
69     * The CollectionsSeparatorChanged system event is generated when a VBucket
70     * changes the separator used for identifying collections in keys. This
71     * must result in a vbucket manifest update and a SystemEvent document is
72     * stored. All separator changes write to the same SystemEvent document.
73     */
74    CollectionsSeparatorChanged
75};
76
77static inline std::string to_string(const SystemEvent se) {
78    switch (se) {
79    case SystemEvent::Collection:
80        return "Collection";
81    case SystemEvent::DeleteCollectionHard:
82        return "DeleteCollectionHard";
83    case SystemEvent::DeleteCollectionSoft:
84        return "DeleteCollectionSoft";
85    case SystemEvent::CollectionsSeparatorChanged:
86        return "CollectionSeparatorChanged";
87    }
88    throw std::invalid_argument("to_string(SystemEvent) unknown " +
89                                std::to_string(int(se)));
90}
91
92class SystemEventFactory {
93public:
94    /**
95     * Make an Item representing the SystemEvent
96     * @param se The SystemEvent being created. The returned Item will have this
97     *           value stored in the flags field.
98     * @param keyExtra Every SystemEvent has defined key, keyExtra is appended
99     *        to the defined key
100     * @param itemSize The returned Item can be requested to allocate a value
101     *        of itemSize. Some SystemEvents will update the value with data to
102     *        be persisted/replicated.
103     * @param seqno An OptionalSeqno - if defined the returned Item will have
104     *        the seqno value set as its bySeqno.
105     */
106    static std::unique_ptr<Item> make(SystemEvent se,
107                                      const std::string& keyExtra,
108                                      size_t itemSize,
109                                      OptionalSeqno seqno);
110
111    static std::unique_ptr<Item> make(const DocKey& key, SystemEvent se);
112
113private:
114    static std::string makeKey(SystemEvent se,
115                               const std::string& keyExtra);
116};
117
118enum class ProcessStatus { Skip, Continue };
119
120/**
121 * SystemEventFlush holds all SystemEvent data for a single invocation of a
122 * vbucket's flush
123 * If the flush encountered no SystemEvents then this class does nothing
124 * If the flush has SystemEvents then this class will ensure the correct
125 * actions occur.
126 */
127class SystemEventFlush {
128public:
129    /**
130     * Get the Item which is updating the collections manifest (if any)
131     *
132     * @return nullptr if no manifest exists or the Item to be used in writing
133     *         a manifest.
134     */
135    const Item* getCollectionsManifestItem() const;
136
137    /**
138     * The flusher passes each item into this function and process determines
139     * what needs to happen (possibly updating the Item).
140     *
141     * This function /may/ take a reference to the ref-counted Item if the Item
142     * is required for a collections manifest update.
143     *
144     * Warning: Even though the input is a const queued_item, the Item* is not
145     * const. This function may call setOperation on the shared item
146     *
147     * @param item an item from the flushers items to flush.
148     * @returns Skip if the flusher should not continue with the item or
149     *          Continue if the flusher can continue the rest of the flushing
150     *          function against the item.
151     */
152    ProcessStatus process(const queued_item& item);
153
154private:
155    /**
156     * Save the item as the item which contains the manifest which will be
157     * used in the flush's update of the vbucket's metadata documents.
158     * The function will only set the them if it has a seqno higher than any
159     * previously saved item.
160     */
161    void saveCollectionsManifestItem(const queued_item& item);
162
163    /**
164     * Shared pointer to an Item which holds collections manifest data that
165     * maybe needed by the flush::commit
166     */
167    queued_item collectionManifestItem;
168};
169
170class SystemEventReplicate {
171public:
172    static ProcessStatus process(const Item& item);
173};
174