YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/docdb/subdocument.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#ifndef YB_DOCDB_SUBDOCUMENT_H_
15
#define YB_DOCDB_SUBDOCUMENT_H_
16
17
#include <assert.h>
18
#include <inttypes.h>
19
#include <stddef.h>
20
#include <stdint.h>
21
#include <string.h>
22
23
#include <limits>
24
#include <map>
25
#include <ostream>
26
#include <string>
27
#include <vector>
28
29
#include "yb/bfql/tserver_opcodes.h"
30
31
#include "yb/docdb/primitive_value.h"
32
33
#include "yb/gutil/int128.h"
34
#include "yb/gutil/integral_types.h"
35
36
namespace yb {
37
namespace docdb {
38
39
// A subdocument could either be a primitive value, or an arbitrarily nested JSON-like data
40
// structure. This class is copyable, but care should be taken to avoid expensive implicit copies.
41
class SubDocument : public PrimitiveValue {
42
 public:
43
44
  explicit SubDocument(ValueType value_type);
45
  SubDocument();
46
47
  ~SubDocument();
48
49
  explicit SubDocument(ListExtendOrder extend_order);
50
51
  // Copy constructor. This is potentially very expensive!
52
  SubDocument(const SubDocument& other);
53
54
  explicit SubDocument(const std::vector<PrimitiveValue> &elements,
55
                       ListExtendOrder extend_order = ListExtendOrder::APPEND);
56
57
0
  SubDocument& operator =(const SubDocument& other) {
58
0
    this->~SubDocument();
59
0
    new(this) SubDocument(other);
60
0
    return *this;
61
0
  }
62
63
  // A good way to construct single-level subdocuments. Not very performant, primarily useful
64
  // for tests.
65
  template<typename T>
66
0
  SubDocument(std::initializer_list<std::initializer_list<T>> elements) {
67
0
    complex_data_structure_ = nullptr;
68
0
    EnsureObjectAllocated();
69
0
    for (const auto& key_value : elements) {
70
0
      CHECK_EQ(2, key_value.size());
71
0
      auto iter = key_value.begin();
72
0
      const auto& key = *iter;
73
0
      ++iter;
74
0
      const auto& value = *iter;
75
0
      CHECK_EQ(0, object_container().count(PrimitiveValue(key)))
76
0
          << "Duplicate key: " << PrimitiveValue(key).ToString();
77
0
      object_container().emplace(PrimitiveValue(key), SubDocument(PrimitiveValue(value)));
78
0
    }
79
0
  }
Unexecuted instantiation: _ZN2yb5docdb11SubDocumentC2IPKcEESt16initializer_listIS5_IT_EE
Unexecuted instantiation: _ZN2yb5docdb11SubDocumentC2IiEESt16initializer_listIS3_IT_EE
80
81
  // Move assignment and constructor.
82
291M
  SubDocument& operator =(SubDocument&& other) {
83
291M
    this->~SubDocument();
84
291M
    MoveFrom(&other);
85
291M
    return *this;
86
291M
  }
87
88
257M
  SubDocument(SubDocument&& other) {
89
257M
    MoveFrom(&other);
90
257M
  }
91
92
216M
  explicit SubDocument(const PrimitiveValue& other) : PrimitiveValue(other) {}
93
16.2M
  explicit SubDocument(PrimitiveValue&& other) : PrimitiveValue(std::move(other)) {}
94
95
  bool operator==(const SubDocument& other) const;
96
0
  bool operator!=(const SubDocument& other) const { return !(*this == other); }
97
98
  // "using" did not let us use the alias when instantiating these classes, so we're using typedef.
99
  typedef std::map<PrimitiveValue, SubDocument> ObjectContainer;
100
  typedef std::vector<SubDocument> ArrayContainer;
101
102
757M
  ObjectContainer& object_container() const {
103
757M
    assert(has_valid_object_container());
104
757M
    return *reinterpret_cast<ObjectContainer*>(complex_data_structure_);
105
757M
  }
106
107
289
  ArrayContainer& array_container() const {
108
289
    assert(has_valid_array_container());
109
289
    return *reinterpret_cast<ArrayContainer*>(complex_data_structure_);
110
289
  }
111
112
  // Interpret the SubDocument as a RedisSet.
113
  // Assume current subdocument is of map type (kObject type)
114
  CHECKED_STATUS ConvertToRedisSet();
115
116
  // Interpret the SubDocument as a RedisTS.
117
  // Assume current subdocument is of map type (kObject type)
118
  CHECKED_STATUS ConvertToRedisTS();
119
120
  // Interpret the SubDocument as a RedisSortedSet.
121
  // Assume current subdocument is of map type (kObject type)
122
  CHECKED_STATUS ConvertToRedisSortedSet();
123
124
  // Interpret the SubDocument as a RedisSortedSet.
125
  // Assume current subdocument is of map type (kObject type)
126
  CHECKED_STATUS ConvertToRedisList();
127
128
  // @return The child subdocument of an object at the given key, or nullptr if this subkey does not
129
  //         exist or this subdocument is not an object.
130
  SubDocument* GetChild(const PrimitiveValue& key);
131
132
  // Returns the number of children for this subdocument.
133
  CHECKED_STATUS NumChildren(size_t *num_children);
134
135
  const SubDocument* GetChild(const PrimitiveValue& key) const;
136
137
  // Returns the child of this object at the given subkey, or default-constructs one if it does not
138
  // exist. Fatals if this is not an object. Never returns nullptr.
139
  // @return A pair of the child at the requested subkey, and a boolean flag indicating whether a
140
  //         new child subdocument has been added.
141
  std::pair<SubDocument*, bool> GetOrAddChild(const PrimitiveValue& key);
142
143
  // Add a list element child of the given value.
144
  void AddListElement(SubDocument&& value);
145
146
  // Set the child subdocument of an object to the given value.
147
  void SetChild(const PrimitiveValue& key, SubDocument&& value);
148
149
112
  void SetChildPrimitive(const PrimitiveValue& key, PrimitiveValue&& value) {
150
112
    SetChild(key, SubDocument(value));
151
112
  }
152
153
13
  void SetChildPrimitive(const PrimitiveValue& key, const PrimitiveValue& value) {
154
13
    SetChild(key, SubDocument(value));
155
13
  }
156
157
  // Creates a JSON-like string representation of this subdocument.
158
  std::string ToString() const;
159
160
  // Attempts to delete a child subdocument of an object with the given key. Fatals if this is not
161
  // an object.
162
  // @return true if a child object was deleted, false if it did not exist.
163
  bool DeleteChild(const PrimitiveValue& key);
164
165
  int object_num_keys() const;
166
167
  // Construct a SubDocument from a QLValuePB.
168
  static SubDocument FromQLValuePB(const QLValuePB& value,
169
                                   SortingType sorting_type,
170
                                   yb::bfql::TSOpcode write_instr = bfql::TSOpcode::kScalarInsert);
171
172
  // Construct a QLValuePB from a SubDocument.
173
  static void ToQLValuePB(const SubDocument& doc,
174
                          const std::shared_ptr<QLType>& ql_type,
175
                          QLValuePB* v);
176
177
 private:
178
179
  CHECKED_STATUS ConvertToCollection(ValueType value_type);
180
181
  // Common code used by move constructor and move assignment.
182
  void MoveFrom(SubDocument* other);
183
184
  void EnsureContainerAllocated();
185
  void EnsureObjectAllocated();
186
187
  bool container_allocated() const;
188
189
1.25G
  bool has_valid_container() const {
190
1.25G
    return complex_data_structure_ != nullptr;
191
1.25G
  }
192
193
  bool has_valid_object_container() const;
194
195
  bool has_valid_array_container() const;
196
197
  friend void SubDocumentToStreamInternal(ostream& out, const SubDocument& subdoc, int indent);
198
  friend void SubDocCollectionToStreamInternal(ostream& out,
199
                                        const SubDocument& subdoc,
200
                                        const int indent,
201
                                        const string& begin,
202
                                        const string& end);
203
204
  // We use a SubDocument as the top-level map from encoded document keys to documents (also
205
  // represented as SubDocuments) in InMemDocDbState, and we need access to object_container()
206
  // from there.
207
  friend class InMemDocDbState;
208
};
209
210
std::ostream& operator <<(ostream& out, const SubDocument& subdoc);
211
212
static_assert(sizeof(SubDocument) == sizeof(PrimitiveValue),
213
              "It is important that we can cast a PrimitiveValue to a SubDocument.");
214
215
}  // namespace docdb
216
}  // namespace yb
217
218
#endif  // YB_DOCDB_SUBDOCUMENT_H_