18350175eSJim Walker/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
28350175eSJim Walker/*
38350175eSJim Walker *     Copyright 2016 Couchbase, Inc
48350175eSJim Walker *
58350175eSJim Walker *   Licensed under the Apache License, Version 2.0 (the "License");
68350175eSJim Walker *   you may not use this file except in compliance with the License.
78350175eSJim Walker *   You may obtain a copy of the License at
88350175eSJim Walker *
98350175eSJim Walker *       http://www.apache.org/licenses/LICENSE-2.0
108350175eSJim Walker *
118350175eSJim Walker *   Unless required by applicable law or agreed to in writing, software
128350175eSJim Walker *   distributed under the License is distributed on an "AS IS" BASIS,
138350175eSJim Walker *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148350175eSJim Walker *   See the License for the specific language governing permissions and
158350175eSJim Walker *   limitations under the License.
168350175eSJim Walker */
178350175eSJim Walker
188350175eSJim Walker#pragma once
198350175eSJim Walker
2064341951SDave Rigby#include "queue_op.h"
218350175eSJim Walker
22b51e6547SBen Huddleston#include <folly/lang/Assume.h>
23002492c6SBen Huddleston#include <folly/lang/Bits.h>
2445fa1633SDave Rigby#include <libcouchstore/couch_common.h>
25d0933f63SDave Rigby#include <memcached/durability_spec.h>
268350175eSJim Walker#include <memcached/protocol_binary.h>
2764341951SDave Rigby#include <memcached/types.h>
28002492c6SBen Huddleston#include <platform/n_byte_integer.h>
2964341951SDave Rigby
3064341951SDave Rigby#include <memory>
3164341951SDave Rigby#include <type_traits>
328350175eSJim Walker
33af9a9259SChristopher Farman// Bitwise masks for manipulating the flexCode variable inside MetaDataV1
34af9a9259SChristopher Farmanconst uint8_t flexCodeMask = 0x7F;
35af9a9259SChristopher Farmanconst uint8_t deleteSourceMask = 0x80;
36af9a9259SChristopher Farman
378b88e592SDave Rigby// These classes are written to disk in couchstore, so we want to (a) have
388b88e592SDave Rigby// a stable binary layout and (b) minimise the space they take.
398b88e592SDave Rigby// Therefore turn on packing of structures. The resulting sizes are verified
408b88e592SDave Rigby// with static_assert()s below to ensure they are always fixed at the expected
418b88e592SDave Rigby// size.
428b88e592SDave Rigby#pragma pack(1)
438350175eSJim Walkerclass MetaData {
448350175eSJim Walkerprotected:
458350175eSJim Walker    /*
468350175eSJim Walker     * Declare the metadata formats in protected visibility.
478350175eSJim Walker     *
484c387968SDave Rigby     * Each version generally extends the previous version, thus in memory you
494c387968SDave Rigby     * have
508350175eSJim Walker     * [V0] or
514c387968SDave Rigby     * [V0][V1]
524c387968SDave Rigby     *
534c387968SDave Rigby     * V3 is special - given that V2 is no longer used (contained fields which
544c387968SDave Rigby     * were subsequently removed); it extends from V1 - i.e.
554c387968SDave Rigby     *
564c387968SDave Rigby     * [V0][V1][V3]
578350175eSJim Walker     */
588350175eSJim Walker    class MetaDataV0 {
598350175eSJim Walker    public:
60dd54a02aSDave Rigby        MetaDataV0() : cas(0), exptime(0), flags(0) {
61dd54a02aSDave Rigby        }
628350175eSJim Walker
638350175eSJim Walker        void initialise(const char* raw) {
648350175eSJim Walker            std::memcpy(this, raw, sizeof(MetaDataV0));
658350175eSJim Walker            // Re-write only cas/exptime to get them in the correct byte-order
668350175eSJim Walker            cas = ntohll(cas);
678350175eSJim Walker            exptime = ntohl(exptime);
688350175eSJim Walker        }
698350175eSJim Walker
708350175eSJim Walker        /*
718350175eSJim Walker         * When V0 is persisted, the cas/exptime are in network byte order.
728350175eSJim Walker         */
738350175eSJim Walker        void prepareForPersistence() {
748350175eSJim Walker            cas = htonll(cas);
758350175eSJim Walker            exptime = htonl(exptime);
768350175eSJim Walker        }
778350175eSJim Walker
788350175eSJim Walker        uint64_t getCas() const {
79dd54a02aSDave Rigby            return cas;
808350175eSJim Walker        }
818350175eSJim Walker
828350175eSJim Walker        void setCas(uint64_t cas) {
838350175eSJim Walker            this->cas = cas;
848350175eSJim Walker        }
858350175eSJim Walker
868350175eSJim Walker        uint32_t getExptime() const {
878350175eSJim Walker            return exptime;
888350175eSJim Walker        }
898350175eSJim Walker
908350175eSJim Walker        void setExptime(uint32_t exptime) {
918350175eSJim Walker            this->exptime = exptime;
928350175eSJim Walker        }
938350175eSJim Walker
948350175eSJim Walker        uint32_t getFlags() const {
958350175eSJim Walker            return flags;
968350175eSJim Walker        }
978350175eSJim Walker
988350175eSJim Walker        void setFlags(uint32_t flags) {
998350175eSJim Walker            this->flags = flags;
1008350175eSJim Walker        }
1018350175eSJim Walker
1028350175eSJim Walker        void copyToBuf(char* raw) const {
1038350175eSJim Walker            // cas and exptime need converting to network byte-order
1048350175eSJim Walker            uint64_t casNBO = htonll(cas);
1058350175eSJim Walker            uint32_t exptimeNBO = htonl(exptime);
1068350175eSJim Walker            std::memcpy(raw, &casNBO, sizeof(uint64_t));
107dd54a02aSDave Rigby            std::memcpy(raw + sizeof(uint64_t), &exptimeNBO, sizeof(uint32_t));
1088350175eSJim Walker            std::memcpy(raw + sizeof(uint64_t) + sizeof(uint32_t),
109dd54a02aSDave Rigby                        &flags,
110dd54a02aSDave Rigby                        sizeof(uint32_t));
1118350175eSJim Walker        }
1128350175eSJim Walker
113dd54a02aSDave Rigby    private:
1148350175eSJim Walker        /*
1158350175eSJim Walker         * V0 knows about CAS, expiry time and flags.
1168350175eSJim Walker         */
1178350175eSJim Walker        uint64_t cas;
118af8487f2SDave Rigby
119af8487f2SDave Rigby        /**
120af8487f2SDave Rigby         * For Alive documents, the time it should expire. For Deleted
121af8487f2SDave Rigby         * documents, the time the document was deleted.
122af8487f2SDave Rigby         * Expressed as seconds since unix epoch (time_t).
123af8487f2SDave Rigby         */
1248350175eSJim Walker        uint32_t exptime;
1258350175eSJim Walker        uint32_t flags;
1268350175eSJim Walker    };
1278350175eSJim Walker
128dd54a02aSDave Rigby    static_assert(sizeof(MetaDataV0) == 16,
129dd54a02aSDave Rigby                  "MetaDataV0 is not the expected size.");
1308350175eSJim Walker
1318350175eSJim Walker    class MetaDataV1 {
1328350175eSJim Walker    public:
133dd54a02aSDave Rigby        MetaDataV1() : flexCode(0), dataType(PROTOCOL_BINARY_RAW_BYTES) {
134dd54a02aSDave Rigby        }
1358350175eSJim Walker
1368350175eSJim Walker        void initialise(const char* raw) {
1378350175eSJim Walker            flexCode = raw[0];
1388350175eSJim Walker            dataType = raw[1];
1398350175eSJim Walker
140af9a9259SChristopher Farman            if (getFlexCode() != FLEX_META_CODE) {
141dd54a02aSDave Rigby                std::invalid_argument(
142dd54a02aSDave Rigby                        "MetaDataV1::initialise illegal "
143dd54a02aSDave Rigby                        "flexCode \"" +
144dd54a02aSDave Rigby                        std::to_string(flexCode) + "\"");
1458350175eSJim Walker            }
1468350175eSJim Walker        }
1478350175eSJim Walker
1488350175eSJim Walker        void setFlexCode() {
1498350175eSJim Walker            setFlexCode(FLEX_META_CODE);
1508350175eSJim Walker        }
1518350175eSJim Walker
1528350175eSJim Walker        void setFlexCode(uint8_t code) {
153af9a9259SChristopher Farman            auto codeIn = code & flexCodeMask;
154af9a9259SChristopher Farman            flexCode = codeIn + (flexCode & deleteSourceMask);
1558350175eSJim Walker        }
1568350175eSJim Walker
1578350175eSJim Walker        uint8_t getFlexCode() const {
158af9a9259SChristopher Farman            return static_cast<uint8_t>(flexCode & flexCodeMask);
1598350175eSJim Walker        }
1608350175eSJim Walker
161cb13da85STrond Norbye        void setDataType(protocol_binary_datatype_t dataType) {
1628350175eSJim Walker            this->dataType = static_cast<uint8_t>(dataType);
1638350175eSJim Walker        }
1648350175eSJim Walker
165cb13da85STrond Norbye        protocol_binary_datatype_t getDataType() const {
166cb13da85STrond Norbye            return static_cast<protocol_binary_datatype_t>(dataType);
1678350175eSJim Walker        }
1688350175eSJim Walker
1698350175eSJim Walker        void copyToBuf(char* raw) const {
1708350175eSJim Walker            raw[0] = flexCode;
1718350175eSJim Walker            raw[1] = dataType;
1728350175eSJim Walker        }
1738350175eSJim Walker
174af9a9259SChristopher Farman        void setDeleteSource(DeleteSource source) {
175af9a9259SChristopher Farman            auto deleteInt = (static_cast<uint8_t>(source)) << 7;
176af9a9259SChristopher Farman            flexCode = deleteInt + (flexCode & flexCodeMask);
177af9a9259SChristopher Farman        }
178af9a9259SChristopher Farman
179af9a9259SChristopher Farman        DeleteSource getDeleteSource() const {
180af9a9259SChristopher Farman            auto deleteBit = flexCode >> 7;
181af9a9259SChristopher Farman            return static_cast<DeleteSource>(deleteBit);
182af9a9259SChristopher Farman        }
183af9a9259SChristopher Farman
1848350175eSJim Walker    private:
1858350175eSJim Walker        /*
1868350175eSJim Walker         * V1 is a 2 byte extension storing datatype
187af9a9259SChristopher Farman         *   0 - flexCode (which also holds deleteSource in bit 7)
1888350175eSJim Walker         *   1 - dataType
1898350175eSJim Walker         */
1908350175eSJim Walker        uint8_t flexCode;
1918350175eSJim Walker        uint8_t dataType;
1928350175eSJim Walker    };
1938350175eSJim Walker
194dd54a02aSDave Rigby    static_assert(sizeof(MetaDataV1) == 2,
195dd54a02aSDave Rigby                  "MetaDataV1 is not the expected size.");
1968350175eSJim Walker
1978350175eSJim Walker    class MetaDataV2 {
1988350175eSJim Walker    public:
1994c387968SDave Rigby        MetaDataV2() = default;
2008350175eSJim Walker
2018350175eSJim Walker        void initialise(const char* raw) {
2028350175eSJim Walker            confResMode = raw[0];
2038350175eSJim Walker        }
2048350175eSJim Walker
2058350175eSJim Walker    private:
2068350175eSJim Walker        /*
2078350175eSJim Walker         * V2 is a 1 byte extension storing the conflict resolution mode.
20858cf5c8eSJim Walker         * This 1 byte extension is never stored out anymore, but may
20958cf5c8eSJim Walker         * exist from down-level ep-engine.
2108350175eSJim Walker         */
2114c387968SDave Rigby        uint8_t confResMode = 0;
2128350175eSJim Walker    };
2138350175eSJim Walker
214dd54a02aSDave Rigby    static_assert(sizeof(MetaDataV2) == 1,
215dd54a02aSDave Rigby                  "MetaDataV2 is not the expected size.");
2168350175eSJim Walker
2174c387968SDave Rigby    /*
2184c387968SDave Rigby     * V3 is a 2 byte[1] extension storing Synchronous Replication state.
2194c387968SDave Rigby     *
2204c387968SDave Rigby     * [1] It /could/ fit all required state into a single byte, however that
2214c387968SDave Rigby     * would mean it's the same size as V2 (1Byte) and we use metadata size to
2224c387968SDave Rigby     * distinguish between the different metadata versions. As such 2bytes are
2234c387968SDave Rigby     * used which logically wastes 1 byte per SyncWrite. If / when we
2244c387968SDave Rigby     * restructure MetaData to say use variable-length encoding with explicit
2254c387968SDave Rigby     * versions (a la flex framing extras) the size could be reduced.
2264c387968SDave Rigby     */
2274c387968SDave Rigby    class MetaDataV3 {
2284c387968SDave Rigby    public:
2294c387968SDave Rigby        // The Operation this represents - maps to queue_op types:
2304c387968SDave Rigby        enum class Operation : uint8_t {
23184251e56SDave Rigby            // A pending sync write. 'level' field defines the durability_level.
2324c387968SDave Rigby            // Present in the DurabilityPrepare namespace.
2334c387968SDave Rigby            Pending = 0,
23484251e56SDave Rigby            // A committed SyncWrite.
2354c387968SDave Rigby            // This exists so we can correctly backfill from disk a Committed
2364c387968SDave Rigby            // mutation and sent out as a DCP_COMMIT to sync_replication
2374c387968SDave Rigby            // enabled DCP clients.
2384c387968SDave Rigby            // Present in the 'normal' (committed) namespace.
2394c387968SDave Rigby            Commit = 1,
24084251e56SDave Rigby            // An aborted SyncWrite.
2414c387968SDave Rigby            // This exists so we can correctly backfill from disk an Aborted
2424c387968SDave Rigby            // mutation and sent out as a DCP_ABORT to sync_replication
2434c387968SDave Rigby            // enabled DCP clients.
2444c387968SDave Rigby            // Present in the DurabilityPrepare namespace.
2454c387968SDave Rigby            Abort = 2,
2464c387968SDave Rigby        };
2474c387968SDave Rigby
2484c387968SDave Rigby        MetaDataV3() = default;
2494c387968SDave Rigby
2504c387968SDave Rigby        void initialise(const char* raw) {
2514c387968SDave Rigby            operation = Operation(raw[0]);
252002492c6SBen Huddleston            uint64_t buf;
253002492c6SBen Huddleston            std::memcpy(&buf, &raw[1], sizeof(cb::uint48_t));
254002492c6SBen Huddleston            details.raw = cb::uint48_t(buf).ntoh();
2554c387968SDave Rigby        };
2564c387968SDave Rigby
2574c387968SDave Rigby        void copyToBuf(char* raw) const {
2584c387968SDave Rigby            raw[0] = char(operation);
259002492c6SBen Huddleston            std::memcpy(&raw[1], &details.raw, sizeof(cb::uint48_t));
2604c387968SDave Rigby        }
2614c387968SDave Rigby
2624c387968SDave Rigby        void setDurabilityOp(queue_op op) {
2634c387968SDave Rigby            switch (op) {
2644c387968SDave Rigby            case queue_op::pending_sync_write:
2654c387968SDave Rigby                operation = Operation::Pending;
2664c387968SDave Rigby                break;
267def65694SDave Rigby            case queue_op::commit_sync_write:
268def65694SDave Rigby                operation = Operation::Commit;
269def65694SDave Rigby                break;
270a81c119dSPaolo Cocchi            case queue_op::abort_sync_write:
271a81c119dSPaolo Cocchi                operation = Operation::Abort;
272a81c119dSPaolo Cocchi                break;
2734c387968SDave Rigby            default:
2744c387968SDave Rigby                throw std::invalid_argument(
2754c387968SDave Rigby                        "MetaDataV3::setDurabilityOp: Unsupported op " +
2764c387968SDave Rigby                        to_string(op));
2774c387968SDave Rigby            }
2784c387968SDave Rigby        }
2794c387968SDave Rigby
2804c387968SDave Rigby        queue_op getDurabilityOp() const {
2814c387968SDave Rigby            switch (operation) {
2824c387968SDave Rigby            case Operation::Pending:
2834c387968SDave Rigby                return queue_op::pending_sync_write;
284def65694SDave Rigby            case Operation::Commit:
285def65694SDave Rigby                return queue_op::commit_sync_write;
286a81c119dSPaolo Cocchi            case Operation::Abort:
287a81c119dSPaolo Cocchi                return queue_op::abort_sync_write;
2884c387968SDave Rigby            default:
2894c387968SDave Rigby                throw std::invalid_argument(
2904c387968SDave Rigby                        "MetaDataV3::getDurabiltyOp: Unsupported op " +
2914c387968SDave Rigby                        std::to_string(int(operation)));
2924c387968SDave Rigby            }
2934c387968SDave Rigby        }
2944c387968SDave Rigby
2954c387968SDave Rigby        cb::durability::Level getDurabilityLevel() const {
296002492c6SBen Huddleston            Expects(operation == Operation::Pending);
297002492c6SBen Huddleston            return static_cast<cb::durability::Level>(details.pending.level);
2984c387968SDave Rigby        }
2994c387968SDave Rigby
3004c387968SDave Rigby        void setDurabilityLevel(cb::durability::Level level_) {
301002492c6SBen Huddleston            Expects(operation == Operation::Pending);
302002492c6SBen Huddleston            details.pending.level = static_cast<char>(level_);
303cfff162eSDave Rigby        }
304cfff162eSDave Rigby
305cfff162eSDave Rigby        bool isPreparedDelete() const {
306002492c6SBen Huddleston            Expects(operation == Operation::Pending);
307002492c6SBen Huddleston            return details.pending.isDelete == 1;
308cfff162eSDave Rigby        }
309cfff162eSDave Rigby
310cfff162eSDave Rigby        void setPreparedDelete(bool isPreparedSyncDelete) {
311002492c6SBen Huddleston            Expects(operation == Operation::Pending);
312002492c6SBen Huddleston            details.pending.isDelete = isPreparedSyncDelete;
313002492c6SBen Huddleston        }
314002492c6SBen Huddleston
315002492c6SBen Huddleston        cb::uint48_t getPrepareSeqno() const {
316002492c6SBen Huddleston            Expects(operation == Operation::Commit ||
317002492c6SBen Huddleston                    operation == Operation::Abort);
318002492c6SBen Huddleston            return details.completed.prepareSeqno;
319002492c6SBen Huddleston        }
320002492c6SBen Huddleston
321002492c6SBen Huddleston        void setPrepareSeqno(cb::uint48_t prepareSeqno) {
322002492c6SBen Huddleston            Expects(operation == Operation::Commit ||
323002492c6SBen Huddleston                    operation == Operation::Abort);
324002492c6SBen Huddleston            details.completed.prepareSeqno = prepareSeqno;
325002492c6SBen Huddleston        }
326002492c6SBen Huddleston
327002492c6SBen Huddleston        void prepareForPersistence() {
328002492c6SBen Huddleston            details.raw = details.raw.hton();
3294c387968SDave Rigby        }
3304c387968SDave Rigby
331942d6f62SJames Harrison        bool isCommit() const {
332942d6f62SJames Harrison            return operation == Operation::Commit;
333942d6f62SJames Harrison        }
334942d6f62SJames Harrison
335a2111545SBen Huddleston        bool isPrepare() const {
336a2111545SBen Huddleston            return operation == Operation::Pending;
337a2111545SBen Huddleston        }
338a2111545SBen Huddleston
3394c387968SDave Rigby    private:
3404c387968SDave Rigby        // Assigning a whole byte to this (see MetaDataV3 class comment)
3414c387968SDave Rigby        // although only currently need 2 bits.
3424c387968SDave Rigby        Operation operation;
3434c387968SDave Rigby
344cfff162eSDave Rigby        // [[if Pending]] Properties of the pending SyncWrite.
345cfff162eSDave Rigby        // Currently using 3 bits out of the available 8 in this byte.
346002492c6SBen Huddleston        union detailsUnion {
347002492c6SBen Huddleston            // Need to supply a default constructor or the compiler will
348002492c6SBen Huddleston            // complain about cb::uint48_t
349002492c6SBen Huddleston            detailsUnion() : raw(0){};
350cfff162eSDave Rigby            struct {
351cfff162eSDave Rigby                // 0:pendingSyncWrite, 1:pendingSyncDelete.
352cfff162eSDave Rigby                uint8_t isDelete : 1;
353cfff162eSDave Rigby                // cb::durability::Level
354cfff162eSDave Rigby                uint8_t level : 2;
355002492c6SBen Huddleston            } pending;
356002492c6SBen Huddleston            struct completedDetails {
357002492c6SBen Huddleston                // prepareSeqno of the completed Sync Write
358002492c6SBen Huddleston                cb::uint48_t prepareSeqno;
359002492c6SBen Huddleston            } completed;
360002492c6SBen Huddleston
361002492c6SBen Huddleston            cb::uint48_t raw;
362002492c6SBen Huddleston        } details;
3634c387968SDave Rigby    };
3644c387968SDave Rigby
365002492c6SBen Huddleston    static_assert(sizeof(MetaDataV3) == 7,
3664c387968SDave Rigby                  "MetaDataV3 is not the expected size.");
3674c387968SDave Rigby
3688350175eSJim Walkerpublic:
3698350175eSJim Walker    enum class Version {
3708350175eSJim Walker        V0, // Cas/Exptime/Flags
3718350175eSJim Walker        V1, // Flex code and datatype
3724c387968SDave Rigby        V2, // Conflict Resolution Mode - not stored, but can be read
3734c387968SDave Rigby        V3, // Synchronous Replication state.
37458cf5c8eSJim Walker        /*
37558cf5c8eSJim Walker         * !!MetaData Warning!!
37658cf5c8eSJim Walker         * Sherlock began storing the V2 MetaData.
37758cf5c8eSJim Walker         * Watson stops storing the V2 MetaData (now storing V1)
37858cf5c8eSJim Walker         *
37958cf5c8eSJim Walker         * Any new MetaData (e.g a V3) we wish to store may cause trouble if it
38058cf5c8eSJim Walker         * has the size of V2, code assumes the version from the size.
38158cf5c8eSJim Walker         */
3828350175eSJim Walker    };
3838350175eSJim Walker
384dd54a02aSDave Rigby    MetaData() {
385dd54a02aSDave Rigby    }
3868350175eSJim Walker
3878350175eSJim Walker    /*
3888350175eSJim Walker     * Construct metadata from a sized_buf, the assumption is that the
3898350175eSJim Walker     * data has come back from couchstore.
3908350175eSJim Walker     */
391dd54a02aSDave Rigby    MetaData(const sized_buf& in) : initVersion(Version::V0) {
3924c387968SDave Rigby        // Expect metadata to be V0, V1, V2 or V3
39358cf5c8eSJim Walker        // V2 part is ignored, but valid to find in storage.
394dd54a02aSDave Rigby        if (in.size < getMetaDataSize(Version::V0) ||
3954c387968SDave Rigby            in.size > getMetaDataSize(Version::V3)) {
3968350175eSJim Walker            throw std::invalid_argument("MetaData::MetaData in.size \"" +
3978350175eSJim Walker                                        std::to_string(in.size) +
3988350175eSJim Walker                                        "\" is out of range.");
3998350175eSJim Walker        }
4008350175eSJim Walker
4018350175eSJim Walker        // Initialise at least the V0 metadata
4028350175eSJim Walker        allMeta.v0.initialise(in.buf);
4038350175eSJim Walker
4048350175eSJim Walker        // The rest depends on in.size
405dd54a02aSDave Rigby        if (in.size >= (sizeof(MetaDataV0) + sizeof(MetaDataV1))) {
4068350175eSJim Walker            // The size extends enough to include V1 meta, initialise that.
4078350175eSJim Walker            allMeta.v1.initialise(in.buf + sizeof(MetaDataV0));
4088350175eSJim Walker            initVersion = Version::V1;
4098350175eSJim Walker        }
4108350175eSJim Walker
41158cf5c8eSJim Walker        // Not initialising V2 from 'in' as V2 is ignored.
4124c387968SDave Rigby
4134c387968SDave Rigby        if (in.size >=
4144c387968SDave Rigby            (sizeof(MetaDataV0) + sizeof(MetaDataV1) + sizeof(MetaDataV3))) {
4154c387968SDave Rigby            // The size extends enough to include V3 meta, initialise that.
4164c387968SDave Rigby            allMeta.v3.initialise(in.buf + sizeof(MetaDataV0) +
4174c387968SDave Rigby                                  sizeof(MetaDataV1));
4184c387968SDave Rigby            initVersion = Version::V3;
4194c387968SDave Rigby        }
4208350175eSJim Walker    }
4218350175eSJim Walker
4228350175eSJim Walker    /*
4238350175eSJim Walker     * The reverse of MetaData(const sized_buf& in), copy the data out
4248350175eSJim Walker     * to a pre-allocated sized_buf ready for passing to couchstore.
4258350175eSJim Walker     */
4268350175eSJim Walker    void copyToBuf(sized_buf& out) const {
4274c387968SDave Rigby        if ((out.size != getMetaDataSize(Version::V1) &&
4284c387968SDave Rigby             (out.size != getMetaDataSize(Version::V3)))) {
4294c387968SDave Rigby            throw std::invalid_argument(
4304c387968SDave Rigby                    "MetaData::copyToBuf o