1/*
2 *     Copyright 2016 Couchbase, Inc
3 *
4 *   Licensed under the Apache License, Version 2.0 (the "License");
5 *   you may not use this file except in compliance with the License.
6 *   You may obtain a copy of the License at
7 *
8 *       http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *   Unless required by applicable law or agreed to in writing, software
11 *   distributed under the License is distributed on an "AS IS" BASIS,
12 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *   See the License for the specific language governing permissions and
14 *   limitations under the License.
15 */
16
17#pragma once
18
19#include <cstdint>
20#include <cstring>
21
22#include <platform/sized_buffer.h>
23
24/**
25 * DocNamespace "Document Namespace"
26 * Meta-data that applies to every document stored in an engine.
27 *
28 * A document "key" with the flag DefaultCollection is not the same document
29 * as "key" with the Collections flag and so on...
30 *
31 * DefaultCollection: describes "legacy" documents stored in a bucket by
32 * clients that do not understand collections.
33 *
34 * Collections: describes documents that have a collection name as part of
35 * the key. E.g. "planet::earth" and "planet::mars" are documents belonging
36 * to a "planet" collection.
37 *
38 * System: describes documents that are created by the system for our own
39 * uses. This is only planned for use with the collection feature where
40 * special keys are interleaved in the users data stream to represent create
41 * and delete events. In future more generic "system documents" maybe
42 * created by the core but until such plans are more clear, ep-engine will
43 * deny the core from performing operations in the System DocNamespace.
44 * DocNamespace values are persisted ot the database and thus are fully
45 * described now ready for future use.
46 */
47enum class DocNamespace : uint8_t {
48    DefaultCollection = 0,
49    Collections = 1,
50    System = 2
51};
52
53template <class T>
54struct DocKeyInterface {
55    size_t size() const {
56        return static_cast<const T*>(this)->size();
57    }
58
59    const uint8_t* data() const {
60        return static_cast<const T*>(this)->data();
61    }
62
63    DocNamespace getDocNamespace() const {
64        return static_cast<const T*>(this)->getDocNamespace();
65    }
66
67    uint32_t hash() const {
68        return hash(size());
69    }
70
71protected:
72    uint32_t hash(size_t bytes) const {
73        uint32_t h = 5381;
74
75        h = ((h << 5) + h) ^ uint32_t(getDocNamespace());
76
77        for (size_t i = 0; i < bytes; i++) {
78            h = ((h << 5) + h) ^ uint32_t(data()[i]);
79        }
80
81        return h;
82    }
83};
84
85/**
86 * DocKey is a non-owning structure used to describe a document keys over
87 * the engine-API. All API commands working with "keys" must specify the
88 * data, length and the namespace with which the document applies to.
89 */
90struct DocKey : DocKeyInterface<DocKey> {
91    /**
92     * Standard constructor - creates a view onto key/nkey
93     */
94    DocKey(const uint8_t* key, size_t nkey, DocNamespace ins)
95        : buffer(key, nkey), doc_namespace(ins) {
96    }
97
98    /**
99     * C-string constructor - only for use with null terminated strings and
100     * creates a view onto key/strlen(key).
101     */
102    DocKey(const char* key, DocNamespace ins)
103        : DocKey(reinterpret_cast<const uint8_t*>(key), std::strlen(key), ins) {
104    }
105
106    /**
107     * const_char_buffer constructor, views the data()/size() of the key
108     */
109    DocKey(const cb::const_char_buffer& key, DocNamespace ins)
110        : DocKey(reinterpret_cast<const uint8_t*>(key.data()),
111                 key.size(),
112                 ins) {
113    }
114
115    /**
116     * Disallow rvalue strings as we would view something which would soon be
117     * out of scope.
118     */
119    DocKey(const std::string&& key, DocNamespace ins) = delete;
120
121    template <class T>
122    DocKey(const DocKeyInterface<T>& key) {
123        buffer.len = key.size();
124        buffer.buf = key.data();
125        doc_namespace = key.getDocNamespace();
126    }
127
128    const uint8_t* data() const {
129        return buffer.data();
130    }
131
132    size_t size() const {
133        return buffer.size();
134    }
135
136    DocNamespace getDocNamespace() const {
137        return doc_namespace;
138    }
139
140private:
141    cb::const_byte_buffer buffer;
142    DocNamespace doc_namespace;
143};
144