196803ff8SJim Walker/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
296803ff8SJim Walker/*
396803ff8SJim Walker *     Copyright 2017 Couchbase, Inc
496803ff8SJim Walker *
596803ff8SJim Walker *   Licensed under the Apache License, Version 2.0 (the "License");
696803ff8SJim Walker *   you may not use this file except in compliance with the License.
796803ff8SJim Walker *   You may obtain a copy of the License at
896803ff8SJim Walker *
996803ff8SJim Walker *       http://www.apache.org/licenses/LICENSE-2.0
1096803ff8SJim Walker *
1196803ff8SJim Walker *   Unless required by applicable law or agreed to in writing, software
1296803ff8SJim Walker *   distributed under the License is distributed on an "AS IS" BASIS,
1396803ff8SJim Walker *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1496803ff8SJim Walker *   See the License for the specific language governing permissions and
1596803ff8SJim Walker *   limitations under the License.
1696803ff8SJim Walker */
1796803ff8SJim Walker
1896803ff8SJim Walker#include "collections/vbucket_manifest_entry.h"
1996803ff8SJim Walker#include "config.h"
2096803ff8SJim Walker
2196803ff8SJim Walker#include <functional>
2296803ff8SJim Walker
2396803ff8SJim Walker#pragma once
2496803ff8SJim Walker
2596803ff8SJim Walkernamespace Collections {
2696803ff8SJim Walkernamespace VB {
2796803ff8SJim Walker
28cc92fc76SJim Walkerclass SerialisedManifestEntry;
29cc92fc76SJim Walker
3096803ff8SJim Walker/**
3196803ff8SJim Walker * A VB::Manifest is serialised into an Item when it is updated. The
3296803ff8SJim Walker * Item carries a copy of the VB::Manifest down to the flusher so that
3396803ff8SJim Walker * a JSON version can be written to persistent storage.
3496803ff8SJim Walker *
3596803ff8SJim Walker * The serialised data is created by VB::Manifest and is a copy of the
3696803ff8SJim Walker * manifest *before* the update is applied. The update being applied to the
3796803ff8SJim Walker * manifest is serialised as the final entry. This is done because the seqno
3896803ff8SJim Walker * of the final entry needs correcting during the creation of the JSON. This
3996803ff8SJim Walker * occurs because the Item is created but cannot be allocated a seqno until it
4096803ff8SJim Walker * is queued, and it is not safe to mutate the Item's value after it is queued.
4196803ff8SJim Walker *
4296803ff8SJim Walker */
4396803ff8SJim Walker
4496803ff8SJim Walker/**
4596803ff8SJim Walker * SerialisedManifest just stores the entry count and can return a pointer
4696803ff8SJim Walker * to the buffer where entries can be written.
4796803ff8SJim Walker */
4896803ff8SJim Walkerclass SerialisedManifest {
4996803ff8SJim Walkerpublic:
5010dad95bSJim Walker    static size_t getObjectSize(uint32_t separatorLen) {
5110dad95bSJim Walker        return sizeof(SerialisedManifest) + separatorLen;
5296803ff8SJim Walker    }
5396803ff8SJim Walker
5496803ff8SJim Walker    void setEntryCount(uint32_t items) {
5596803ff8SJim Walker        itemCount = items;
5696803ff8SJim Walker    }
5796803ff8SJim Walker
5896803ff8SJim Walker    uint32_t getEntryCount() const {
5996803ff8SJim Walker        return itemCount;
6096803ff8SJim Walker    }
6196803ff8SJim Walker
6210dad95bSJim Walker    std::string getSeparator() const {
6310dad95bSJim Walker        return {getSeparatorPtr(), separatorLen};
6410dad95bSJim Walker    }
6510dad95bSJim Walker
66cc92fc76SJim Walker    cb::const_char_buffer getSeparatorBuffer() const {
67cc92fc76SJim Walker        return {getSeparatorPtr(), separatorLen};
68cc92fc76SJim Walker    }
69cc92fc76SJim Walker
70cc92fc76SJim Walker    /**
71cc92fc76SJim Walker     * For code to locate the final entry this function is used to calculate
72cc92fc76SJim Walker     * a byte offset so that getFinalManifestEntry can return the final entry
73cc92fc76SJim Walker     * without any iteration.
74cc92fc76SJim Walker     *
75cc92fc76SJim Walker     * @param sme pointer to the final entry constructed in the serial manifest.
76cc92fc76SJim Walker     */
77cc92fc76SJim Walker    void calculateFinalEntryOffest(const SerialisedManifestEntry* sme) {
78cc92fc76SJim Walker        finalEntryOffset =
79cc92fc76SJim Walker                reinterpret_cast<const char*>(sme) - getManifestEntryBuffer();
80cc92fc76SJim Walker    }
81cc92fc76SJim Walker
8296803ff8SJim Walker    /**
8396803ff8SJim Walker     * Return a non const pointer to where the entries can be written
8496803ff8SJim Walker     */
8596803ff8SJim Walker    char* getManifestEntryBuffer() {
8610dad95bSJim Walker        return getSeparatorPtr() + separatorLen;
8796803ff8SJim Walker    }
8896803ff8SJim Walker
8996803ff8SJim Walker    /**
9096803ff8SJim Walker     * Return a const pointer from where the entries can be read
9196803ff8SJim Walker     */
9296803ff8SJim Walker    const char* getManifestEntryBuffer() const {
9310dad95bSJim Walker        return getSeparatorPtr() + separatorLen;
9496803ff8SJim Walker    }
9596803ff8SJim Walker
96cc92fc76SJim Walker    /**
97cc92fc76SJim Walker     * Return the final entry in the SerialManifest - this entry is always the
98cc92fc76SJim Walker     * entry which is being created or deleted. DCP event generation can use
99cc92fc76SJim Walker     * this method to obtain the data needed to send to replicas.
100cc92fc76SJim Walker     *
101cc92fc76SJim Walker     * @return The entry which is being added or removed.
102cc92fc76SJim Walker     */
103cc92fc76SJim Walker    const SerialisedManifestEntry* getFinalManifestEntry() const {
104cc92fc76SJim Walker        return reinterpret_cast<const SerialisedManifestEntry*>(
105cc92fc76SJim Walker                getManifestEntryBuffer() + finalEntryOffset);
106cc92fc76SJim Walker    }
107cc92fc76SJim Walker
108f9444d17SJim Walker    uid_t getManifestUid() const {
109f9444d17SJim Walker        return manifestUid;
110f9444d17SJim Walker    }
111f9444d17SJim Walker
11296803ff8SJim Walkerprivate:
11310dad95bSJim Walker
11410dad95bSJim Walker    friend Collections::VB::Manifest;
115cc92fc76SJim Walker    static SerialisedManifest* make(char* address,
116cc92fc76SJim Walker                                    const std::string& separator,
117f9444d17SJim Walker                                    uid_t manifestUid,
118cc92fc76SJim Walker                                    cb::char_buffer out) {
119f9444d17SJim Walker        return new (address) SerialisedManifest(separator, manifestUid, out);
12010dad95bSJim Walker    }
12110dad95bSJim Walker
12210dad95bSJim Walker    /**
12310dad95bSJim Walker     * Construct a SerialisedManifest to have 0 items and the separator string.
12410dad95bSJim Walker     *
12510dad95bSJim Walker     * @param separator The separator for the manifest
12610dad95bSJim Walker     * @param out The buffer into which this object is being constructed
12710dad95bSJim Walker     * @throws length_error if the consruction would access outside of out
12810dad95bSJim Walker     */
129cc92fc76SJim Walker    SerialisedManifest(const std::string& separator,
130f9444d17SJim Walker                       uid_t manifestUid,
131f9444d17SJim Walker                       cb::char_buffer out)
132f9444d17SJim Walker        : itemCount(0),
133f9444d17SJim Walker          separatorLen(separator.size()),
134f9444d17SJim Walker          finalEntryOffset(0),
135f9444d17SJim Walker          manifestUid(manifestUid) {
13610dad95bSJim Walker        if (!((out.data() + out.size()) >=
13710dad95bSJim Walker              (reinterpret_cast<char*>(this) +
13810dad95bSJim Walker               getObjectSize(separator.size())))) {
1399160b844SJim Walker            throw std::length_error(
1409160b844SJim Walker                    "SerialisedManifest::tryConstruction with separator.size " +
1419160b844SJim Walker                    std::to_string(separator.size()) +
1429160b844SJim Walker                    " exceeds the buffer of size " +
1439160b844SJim Walker                    std::to_string(out.size()));
14410dad95bSJim Walker        }
14510dad95bSJim Walker        std::copy_n(separator.data(), separator.size(), getSeparatorPtr());
14610dad95bSJim Walker    }
14710dad95bSJim Walker
14810dad95bSJim Walker    const char* getSeparatorPtr() const {
14910dad95bSJim Walker        return reinterpret_cast<const char*>(this + 1);
15010dad95bSJim Walker    }
15110dad95bSJim Walker
15210dad95bSJim Walker    char* getSeparatorPtr() {
15310dad95bSJim Walker        return reinterpret_cast<char*>(this + 1);
15410dad95bSJim Walker    }
15510dad95bSJim Walker
15696803ff8SJim Walker    uint32_t itemCount;
15710dad95bSJim Walker    uint32_t separatorLen;
158cc92fc76SJim Walker    uint32_t finalEntryOffset;
159f9444d17SJim Walker    uid_t manifestUid;
16096803ff8SJim Walker};
16196803ff8SJim Walker
16296803ff8SJim Walkerclass SerialisedManifestEntry {
16396803ff8SJim Walkerpublic:
164d7615449SJim Walker    /**
165d7615449SJim Walker     * Object is not copyable or movable
166d7615449SJim Walker     */
167d7615449SJim Walker    SerialisedManifestEntry(const SerialisedManifestEntry& other) = delete;
168d7615449SJim Walker    SerialisedManifestEntry(SerialisedManifestEntry&& other) = delete;
16996803ff8SJim Walker
17096803ff8SJim Walker    static size_t getObjectSize(size_t collectionNameLen) {
171d7615449SJim Walker        return sizeof(SerialisedManifestEntry) + collectionNameLen;
17296803ff8SJim Walker    }
17396803ff8SJim Walker
17496803ff8SJim Walker    size_t getObjectSize() const {
17596803ff8SJim Walker        return getObjectSize(getCollectionNameLen());
17696803ff8SJim Walker    }
17796803ff8SJim Walker
1789160b844SJim Walker    uid_t getUid() const {
1799160b844SJim Walker        return uid;
180cc92fc76SJim Walker    }
181cc92fc76SJim Walker
1829160b844SJim Walker    void setUid(uid_t uid) {
1839160b844SJim Walker        this->uid = uid;
18496803ff8SJim Walker    }
18596803ff8SJim Walker
1863c80abaeSJim Walker    /**
1879160b844SJim Walker     * @return the entry's collection name as a const char buffer
1883c80abaeSJim Walker     */
189cc92fc76SJim Walker    cb::const_char_buffer getCollectionName() const {
190cc92fc76SJim Walker        return {getCollectionNamePtr(), size_t(collectionNameLen)};
191cc92fc76SJim Walker    }
192cc92fc76SJim Walker
19396803ff8SJim Walker    size_t getCollectionNameLen() const {
19496803ff8SJim Walker        return collectionNameLen;
19596803ff8SJim Walker    }
19696803ff8SJim Walker
19796803ff8SJim Walker    const char* nextEntry() const {
19896803ff8SJim Walker        return reinterpret_cast<const char*>(this) + getObjectSize();
19996803ff8SJim Walker    }
20096803ff8SJim Walker
20196803ff8SJim Walker    char* nextEntry() {
20296803ff8SJim Walker        return const_cast<char*>(
20396803ff8SJim Walker                static_cast<const SerialisedManifestEntry*>(this)->nextEntry());
20496803ff8SJim Walker    }
20596803ff8SJim Walker
20696803ff8SJim Walker    std::string toJson() const {
20796803ff8SJim Walker        return toJson(startSeqno, endSeqno);
20896803ff8SJim Walker    }
20996803ff8SJim Walker
210a9dea599SJim Walker    std::string toJsonCreateOrDelete(bool isCollectionDelete,
211a9dea599SJim Walker                                     int64_t correctedSeqno) const {
212a9dea599SJim Walker        if (isCollectionDelete) {
21396803ff8SJim Walker            return toJson(startSeqno, correctedSeqno);
21496803ff8SJim Walker        }
215a9dea599SJim Walker        return toJson(correctedSeqno, endSeqno);
216a9dea599SJim Walker    }
21796803ff8SJim Walker
218a9dea599SJim Walker    std::string toJsonResetEnd() const {
219a9dea599SJim Walker        return toJson(startSeqno, StoredValue::state_collection_open);
22096803ff8SJim Walker    }
22196803ff8SJim Walker
22296803ff8SJim Walkerprivate:
22396803ff8SJim Walker    friend Collections::VB::Manifest;
22496803ff8SJim Walker    static SerialisedManifestEntry* make(
22596803ff8SJim Walker            char* address,
22696803ff8SJim Walker            const Collections::VB::ManifestEntry& me,
22796803ff8SJim Walker            cb::char_buffer out) {
22896803ff8SJim Walker        return new (address) SerialisedManifestEntry(me, out);
22996803ff8SJim Walker    }
23096803ff8SJim Walker
23196803ff8SJim Walker    static SerialisedManifestEntry* make(char* address,
2329160b844SJim Walker                                         Identifier identifier,
23396803ff8SJim Walker                                         cb::char_buffer out) {
2349160b844SJim Walker        return new (address) SerialisedManifestEntry(identifier, out);
23596803ff8SJim Walker    }
23696803ff8SJim Walker
23796803ff8SJim Walker    SerialisedManifestEntry(const Collections::VB::ManifestEntry& me,
23896803ff8SJim Walker                            cb::char_buffer out) {
2399160b844SJim Walker        tryConstruction(
2409160b844SJim Walker                out, me.getIdentifier(), me.getStartSeqno(), me.getEndSeqno());
24196803ff8SJim Walker    }
24296803ff8SJim Walker
2439160b844SJim Walker    SerialisedManifestEntry(Identifier identifier, cb::char_buffer out) {
2449160b844SJim Walker        tryConstruction(out, identifier, 0, StoredValue::state_collection_open);
24596803ff8SJim Walker    }
24696803ff8SJim Walker
247d7615449SJim Walker    /**
248d7615449SJim Walker     * The collection name is stored in memory allocated after this object.
249d7615449SJim Walker     *
250d7615449SJim Walker     * @return pointer to the collection name, located at the address after
251d7615449SJim Walker     *         'this'.
252d7615449SJim Walker     */
253cc92fc76SJim Walker    char* getCollectionNamePtr() {
254d7615449SJim Walker        return reinterpret_cast<char*>(this + 1);
255d7615449SJim Walker    }
256d7615449SJim Walker
257d7615449SJim Walker    /**
258d7615449SJim Walker     * The collection name is stored in memory allocated after this object.
259d7615449SJim Walker     *
260d7615449SJim Walker     * @return const pointer to the collection name, located at the address
261d7615449SJim Walker     *         after 'this'.
262d7615449SJim Walker     */
263cc92fc76SJim Walker    const char* getCollectionNamePtr() const {
264d7615449SJim Walker        return reinterpret_cast<const char*>(this + 1);
265d7615449SJim Walker    }
266d7615449SJim Walker
26796803ff8SJim Walker    /**
26896803ff8SJim Walker     * throw an exception if the construction of a serialised object overflows
26996803ff8SJim Walker     * the memory allocation represented by out.
27096803ff8SJim Walker     *
27196803ff8SJim Walker     * @param out The buffer we are writing to
2729160b844SJim Walker     * @param identifier The Identifier of the collection to save in this entry
27396803ff8SJim Walker     * @param startSeqno The startSeqno value to be used
27496803ff8SJim Walker     * @param endSeqno The endSeqno value to be used
275cc92fc76SJim Walker     * @throws std::length_error if the function would write outside of out's
276cc92fc76SJim Walker     *         bounds.
27796803ff8SJim Walker     */
27896803ff8SJim Walker    void tryConstruction(cb::char_buffer out,
2799160b844SJim Walker                         Identifier identifier,
28096803ff8SJim Walker                         int64_t startSeqno,
2819160b844SJim Walker                         int64_t endSeqno) {
28296803ff8SJim Walker        if (!((out.data() + out.size()) >=
28396803ff8SJim Walker              (reinterpret_cast<char*>(this) +
2849160b844SJim Walker               getObjectSize(identifier.getName().size())))) {
2859160b844SJim Walker            throw std::length_error(
2869160b844SJim Walker                    "SerialisedManifestEntry::tryConstruction with collection "
2879160b844SJim Walker                    "size " +
2889160b844SJim Walker                    std::to_string(identifier.getName().size()) +
2899160b844SJim Walker                    " exceeds the buffer of size " +
2909160b844SJim Walker                    std::to_string(out.size()));
29196803ff8SJim Walker        }
2929160b844SJim Walker        this->uid = identifier.getUid();
29396803ff8SJim Walker        this->startSeqno = startSeqno;
29496803ff8SJim Walker        this->endSeqno = endSeqno;
2959160b844SJim Walker        this->collectionNameLen = identifier.getName().size();
296cc92fc76SJim Walker        std::memcpy(getCollectionNamePtr(),
2979160b844SJim Walker                    identifier.getName().data(),
29896803ff8SJim Walker                    this->collectionNameLen);
29996803ff8SJim Walker    }
30096803ff8SJim Walker
30196803ff8SJim Walker    /**
30296803ff8SJim Walker     * Return a std::string JSON representation of this object with the callers
30396803ff8SJim Walker     * chosen startSeqno/endSeqno (based on isDelete)
30496803ff8SJim Walker     *
30596803ff8SJim Walker     * @param _startSeqno The startSeqno value to be used
30696803ff8SJim Walker     * @param _endSeqno The endSeqno value to be used
307cc92fc76SJim Walker     * @return A std::string JSON object for this object.
30896803ff8SJim Walker     */
30996803ff8SJim Walker    std::string toJson(int64_t _startSeqno, int64_t _endSeqno) const {
310cd98cc03SJim Walker        std::stringstream json;
311cd98cc03SJim Walker        json << R"({"name":")"
312cd98cc03SJim Walker             << std::string(getCollectionNamePtr(), collectionNameLen)
313cd98cc03SJim Walker             << R"(","uid":")" << std::hex << uid << "\"," << std::dec
314cd98cc03SJim Walker             << R"("startSeqno":")" << _startSeqno << "\","
315cd98cc03SJim Walker             << R"("endSeqno":")" << _endSeqno << "\"}";
316cd98cc03SJim Walker        return json.str();
31796803ff8SJim Walker    }
31896803ff8SJim Walker
319d7615449SJim Walker    int32_t collectionNameLen;
320a9dea599SJim Walker    uid_t uid;
32196803ff8SJim Walker    int64_t startSeqno;
32296803ff8SJim Walker    int64_t endSeqno;
32396803ff8SJim Walker};
32496803ff8SJim Walker
32596803ff8SJim Walkerstatic_assert(std::is_standard_layout<SerialisedManifestEntry>::value,
32696803ff8SJim Walker              "SerialisedManifestEntry must satisfy StandardLayoutType");
32796803ff8SJim Walker
32896803ff8SJim Walker} // end namespace VB
329d7615449SJim Walker} // end namespace Collections