12f12cd1aSJim Walker/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
22f12cd1aSJim Walker/*
32f12cd1aSJim Walker *     Copyright 2017 Couchbase, Inc
42f12cd1aSJim Walker *
52f12cd1aSJim Walker *   Licensed under the Apache License, Version 2.0 (the "License");
62f12cd1aSJim Walker *   you may not use this file except in compliance with the License.
72f12cd1aSJim Walker *   You may obtain a copy of the License at
82f12cd1aSJim Walker *
92f12cd1aSJim Walker *       http://www.apache.org/licenses/LICENSE-2.0
102f12cd1aSJim Walker *
112f12cd1aSJim Walker *   Unless required by applicable law or agreed to in writing, software
122f12cd1aSJim Walker *   distributed under the License is distributed on an "AS IS" BASIS,
132f12cd1aSJim Walker *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
142f12cd1aSJim Walker *   See the License for the specific language governing permissions and
152f12cd1aSJim Walker *   limitations under the License.
162f12cd1aSJim Walker */
172f12cd1aSJim Walker
182f12cd1aSJim Walker#include "systemevent.h"
19b7acc401SDave Rigby
202f12cd1aSJim Walker#include "collections/collections_types.h"
213fd9c0fcSJim Walker#include "collections/vbucket_manifest.h"
223fd9c0fcSJim Walker#include "dcp/response.h"
23b7acc401SDave Rigby#include "item.h"
24d7615449SJim Walker#include "kvstore.h"
252f12cd1aSJim Walker
26e57f09f4SJim Walkerstd::unique_ptr<Item> SystemEventFactory::make(
27e57f09f4SJim Walker        SystemEvent se,
28e57f09f4SJim Walker        const std::string& keyExtra,
29e57f09f4SJim Walker        size_t itemSize,
30e57f09f4SJim Walker        OptionalSeqno seqno) {
31dea18910SJim Walker    std::string key = makeKey(se, keyExtra);
322f12cd1aSJim Walker
332f12cd1aSJim Walker    auto item = std::make_unique<Item>(DocKey(key, DocNamespace::System),
342f12cd1aSJim Walker                                       uint32_t(se) /*flags*/,
352f12cd1aSJim Walker                                       0 /*exptime*/,
362f12cd1aSJim Walker                                       nullptr, /*no data to copy-in*/
372f12cd1aSJim Walker                                       itemSize);
382f12cd1aSJim Walker
39cc92fc76SJim Walker    if (seqno) {
40cc92fc76SJim Walker        item->setBySeqno(seqno.value());
41cc92fc76SJim Walker    }
42cc92fc76SJim Walker
432f12cd1aSJim Walker    return item;
442f12cd1aSJim Walker}
45d7615449SJim Walker
46dea18910SJim Walkerstd::unique_ptr<Item> SystemEventFactory::make(const DocKey& key,
47dea18910SJim Walker                                               SystemEvent se) {
48dea18910SJim Walker    if (key.getDocNamespace() != DocNamespace::System) {
49dea18910SJim Walker        throw std::invalid_argument(
50dea18910SJim Walker                "SystemEventFactory::::make cannot use key with namespace: " +
51dea18910SJim Walker                std::to_string(int(key.getDocNamespace())));
52dea18910SJim Walker    }
53dea18910SJim Walker
54dea18910SJim Walker    auto item = std::make_unique<Item>(key,
55dea18910SJim Walker                                       uint32_t(se) /*flags*/,
56dea18910SJim Walker                                       0 /*exptime*/,
57dea18910SJim Walker                                       nullptr, /*no data to copy-in*/
58dea18910SJim Walker                                       0);
59dea18910SJim Walker
60dea18910SJim Walker    return item;
61dea18910SJim Walker}
62dea18910SJim Walker
63e57f09f4SJim Walker// Build a key using the separator so we can split it if needed
64e57f09f4SJim Walkerstd::string SystemEventFactory::makeKey(SystemEvent se,
65e57f09f4SJim Walker                                        const std::string& keyExtra) {
66dea18910SJim Walker    std::string key;
67e57f09f4SJim Walker    switch (se) {
68a9dea599SJim Walker    case SystemEvent::Collection:
69dea18910SJim Walker        // $collection:<collection-name>
70dea18910SJim Walker        key = Collections::SystemEventPrefixWithSeparator + keyExtra;
71a9dea599SJim Walker        break;
72e57f09f4SJim Walker    case SystemEvent::DeleteCollectionSoft:
73e57f09f4SJim Walker    case SystemEvent::DeleteCollectionHard: {
74dea18910SJim Walker        // $collections:delete:<collection-name>
75dea18910SJim Walker        key = Collections::DeleteKey + keyExtra;
76e57f09f4SJim Walker        break;
77e57f09f4SJim Walker    }
78e57f09f4SJim Walker    case SystemEvent::CollectionsSeparatorChanged: {
79dea18910SJim Walker        // $collections_separator:<key-extra>
80dea18910SJim Walker        key = Collections::SeparatorChangePrefixWithSeparator + keyExtra;
81e57f09f4SJim Walker        break;
82e57f09f4SJim Walker    }
83e57f09f4SJim Walker    }
84e57f09f4SJim Walker    return key;
85e57f09f4SJim Walker}
86e57f09f4SJim Walker
87862dece9SJim WalkerProcessStatus SystemEventFlush::process(const queued_item& item) {
88d7615449SJim Walker    if (item->getOperation() != queue_op::system_event) {
89862dece9SJim Walker        return ProcessStatus::Continue;
90d7615449SJim Walker    }
91d7615449SJim Walker
92d7615449SJim Walker    switch (SystemEvent(item->getFlags())) {
93dea18910SJim Walker    case SystemEvent::Collection: {
944885256fSJim Walker        saveCollectionsManifestItem(item); // Updates manifest
95862dece9SJim Walker        return ProcessStatus::Continue; // And flushes an item
96862dece9SJim Walker    }
97dea18910SJim Walker    case SystemEvent::CollectionsSeparatorChanged: {
98dea18910SJim Walker        if (!item->isDeleted()) {
99dea18910SJim Walker            saveCollectionsManifestItem(item); // Updates manifest
100dea18910SJim Walker        }
101dea18910SJim Walker        return ProcessStatus::Continue; // And flushes an item
102dea18910SJim Walker    }
103a9dea599SJim Walker    case SystemEvent::DeleteCollectionHard:
104a9dea599SJim Walker    case SystemEvent::DeleteCollectionSoft: {
105862dece9SJim Walker        saveCollectionsManifestItem(item); // Updates manifest
106862dece9SJim Walker        return ProcessStatus::Skip; // But skips flushing the item
107d7615449SJim Walker    }
108d7615449SJim Walker    }
109d7615449SJim Walker
110d7615449SJim Walker    throw std::invalid_argument("SystemEventFlush::process unknown event " +
111d7615449SJim Walker                                std::to_string(item->getFlags()));
112d7615449SJim Walker}
113d7615449SJim Walker
114d7615449SJim Walkerconst Item* SystemEventFlush::getCollectionsManifestItem() const {
115d7615449SJim Walker    return collectionManifestItem.get();
116d7615449SJim Walker}
117d7615449SJim Walker
118d7615449SJim Walkervoid SystemEventFlush::saveCollectionsManifestItem(const queued_item& item) {
119d7615449SJim Walker    // For a given checkpoint only the highest system event should be the
120d7615449SJim Walker    // one which writes the manifest
121d7615449SJim Walker    if ((collectionManifestItem &&
122d7615449SJim Walker         item->getBySeqno() > collectionManifestItem->getBySeqno()) ||
123d7615449SJim Walker        !collectionManifestItem) {
124d7615449SJim Walker        collectionManifestItem = item;
125d7615449SJim Walker    }
1263fd9c0fcSJim Walker}
1273fd9c0fcSJim Walker
1283fd9c0fcSJim WalkerProcessStatus SystemEventReplicate::process(const Item& item) {
1293fd9c0fcSJim Walker    if (item.shouldReplicate()) {
1303fd9c0fcSJim Walker        if (item.getOperation() != queue_op::system_event) {
1313fd9c0fcSJim Walker            // Not a system event, so no further filtering
1323fd9c0fcSJim Walker            return ProcessStatus::Continue;
1333fd9c0fcSJim Walker        } else {
1343fd9c0fcSJim Walker            switch (SystemEvent(item.getFlags())) {
135a9dea599SJim Walker            case SystemEvent::Collection:
1363fd9c0fcSJim Walker            case SystemEvent::CollectionsSeparatorChanged:
137a9dea599SJim Walker                // Collection and change separator events both replicate
1383fd9c0fcSJim Walker                return ProcessStatus::Continue;
1393fd9c0fcSJim Walker            case SystemEvent::DeleteCollectionHard:
1403fd9c0fcSJim Walker            case SystemEvent::DeleteCollectionSoft: {
1413fd9c0fcSJim Walker                // Delete H/S do not replicate
1423fd9c0fcSJim Walker                return ProcessStatus::Skip;
1433fd9c0fcSJim Walker            }
1443fd9c0fcSJim Walker            }
1453fd9c0fcSJim Walker        }
1463fd9c0fcSJim Walker    }
1473fd9c0fcSJim Walker    return ProcessStatus::Skip;
1483fd9c0fcSJim Walker}
1493fd9c0fcSJim Walker
1503fd9c0fcSJim Walkerstd::unique_ptr<SystemEventProducerMessage> SystemEventProducerMessage::make(
151db9b7df5SDave Rigby        uint32_t opaque, const queued_item& item) {
1523fd9c0fcSJim Walker    switch (SystemEvent(item->getFlags())) {
153a9dea599SJim Walker    case SystemEvent::Collection: {
1549160b844SJim Walker        // Note: constructor is private and make_unique is a pain to make friend
1557fdc2e2dSJim Walker        return std::unique_ptr<CollectionsProducerMessage>{
1567fdc2e2dSJim Walker                new CollectionsProducerMessage(
157cd24b1b3SJim Walker                        opaque,
158cd24b1b3SJim Walker                        item,
159cd24b1b3SJim Walker                        Collections::VB::Manifest::getSystemEventData(
160cd24b1b3SJim Walker                                {item->getData(), item->getNBytes()}))};
1613fd9c0fcSJim Walker    }
1623fd9c0fcSJim Walker    case SystemEvent::CollectionsSeparatorChanged: {
1639160b844SJim Walker        // Note: constructor is private and make_unique is a pain to make friend
1647fdc2e2dSJim Walker        return std::unique_ptr<ChangeSeparatorProducerMessage>{
165cd24b1b3SJim Walker                new ChangeSeparatorProducerMessage(
166cd24b1b3SJim Walker                        opaque,
167cd24b1b3SJim Walker                        item,
168cd24b1b3SJim Walker                        Collections::VB::Manifest::getSystemEventSeparatorData(
169cd24b1b3SJim Walker                                {item->getData(), item->getNBytes()}))};
1703fd9c0fcSJim Walker    }
1713fd9c0fcSJim Walker    case SystemEvent::DeleteCollectionHard:
1723fd9c0fcSJim Walker    case SystemEvent::DeleteCollectionSoft:
1739160b844SJim Walker        break;
1743fd9c0fcSJim Walker    }
1753fd9c0fcSJim Walker
1769160b844SJim Walker    throw std::logic_error("SystemEventProducerMessage::make not valid for " +
1779160b844SJim Walker                           std::to_string(item->getFlags()));
1783fd9c0fcSJim Walker}
179