1 /**
2 * @file metadata.cc
3 *
4 * @section LICENSE
5 *
6 * The MIT License
7 *
8 * @copyright Copyright (c) 2017-2021 TileDB, Inc.
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
27 *
28 * @section DESCRIPTION
29 *
30 * This file implements class Metadata.
31 */
32
33 #include "tiledb/sm/metadata/metadata.h"
34 #include "tiledb/common/logger.h"
35 #include "tiledb/sm/buffer/buffer.h"
36 #include "tiledb/sm/enums/datatype.h"
37 #include "tiledb/sm/misc/utils.h"
38 #include "tiledb/sm/misc/uuid.h"
39
40 #include <iostream>
41 #include <sstream>
42
43 using namespace tiledb::common;
44
45 namespace tiledb {
46 namespace sm {
47
48 /* ********************************* */
49 /* CONSTRUCTORS & DESTRUCTORS */
50 /* ********************************* */
51
Metadata()52 Metadata::Metadata() {
53 auto t = utils::time::timestamp_now_ms();
54 timestamp_range_ = std::make_pair(t, t);
55 }
56
Metadata(const Metadata & rhs)57 Metadata::Metadata(const Metadata& rhs)
58 : metadata_map_(rhs.metadata_map_)
59 , timestamp_range_(rhs.timestamp_range_)
60 , loaded_metadata_uris_(rhs.loaded_metadata_uris_)
61 , uri_(rhs.uri_) {
62 if (!rhs.metadata_index_.empty())
63 build_metadata_index();
64 }
65
66 Metadata::~Metadata() = default;
67
68 /* ********************************* */
69 /* API */
70 /* ********************************* */
71
clear()72 void Metadata::clear() {
73 metadata_map_.clear();
74 metadata_index_.clear();
75 loaded_metadata_uris_.clear();
76 timestamp_range_ = std::make_pair(0, 0);
77 uri_ = URI();
78 }
79
get_uri(const URI & array_uri,URI * meta_uri)80 Status Metadata::get_uri(const URI& array_uri, URI* meta_uri) {
81 if (uri_.to_string().empty())
82 RETURN_NOT_OK(generate_uri(array_uri));
83
84 *meta_uri = uri_;
85 return Status::Ok();
86 }
87
generate_uri(const URI & array_uri)88 Status Metadata::generate_uri(const URI& array_uri) {
89 std::string uuid;
90 RETURN_NOT_OK(uuid::generate_uuid(&uuid, false));
91
92 std::stringstream ss;
93 ss << "__" << timestamp_range_.first << "_" << timestamp_range_.second << "_"
94 << uuid;
95 uri_ = array_uri.join_path(constants::array_metadata_folder_name)
96 .join_path(ss.str());
97
98 return Status::Ok();
99 }
100
deserialize(const std::vector<tdb_shared_ptr<Buffer>> & metadata_buffs)101 Status Metadata::deserialize(
102 const std::vector<tdb_shared_ptr<Buffer>>& metadata_buffs) {
103 clear();
104
105 if (metadata_buffs.empty())
106 return Status::Ok();
107
108 uint32_t key_len;
109 char del;
110 size_t value_len;
111 for (const auto& buff : metadata_buffs) {
112 // Iterate over all items
113 buff->reset_offset();
114 while (buff->offset() != buff->size()) {
115 RETURN_NOT_OK(buff->read(&key_len, sizeof(uint32_t)));
116 std::string key((const char*)buff->cur_data(), key_len);
117 buff->advance_offset(key_len);
118 RETURN_NOT_OK(buff->read(&del, sizeof(char)));
119
120 metadata_map_.erase(key);
121
122 // Handle deletion
123 if (del)
124 continue;
125
126 MetadataValue value_struct;
127 value_struct.del_ = del;
128 RETURN_NOT_OK(buff->read(&value_struct.type_, sizeof(char)));
129 RETURN_NOT_OK(buff->read(&value_struct.num_, sizeof(uint32_t)));
130 if (value_struct.num_) {
131 value_len = value_struct.num_ *
132 datatype_size(static_cast<Datatype>(value_struct.type_));
133 value_struct.value_.resize(value_len);
134 RETURN_NOT_OK(buff->read((void*)value_struct.value_.data(), value_len));
135 }
136
137 // Insert to metadata
138 metadata_map_.emplace(std::make_pair(key, std::move(value_struct)));
139 }
140 }
141
142 build_metadata_index();
143 // Note: `metadata_map_` and `metadata_index_` are immutable after this point
144
145 return Status::Ok();
146 }
147
serialize(Buffer * buff) const148 Status Metadata::serialize(Buffer* buff) const {
149 // Do nothing if there are no metadata to serialize
150 if (metadata_map_.empty())
151 return Status::Ok();
152
153 for (const auto& meta : metadata_map_) {
154 auto key_len = (uint32_t)meta.first.size();
155 RETURN_NOT_OK(buff->write(&key_len, sizeof(uint32_t)));
156 RETURN_NOT_OK(buff->write(meta.first.data(), meta.first.size()));
157 const auto& value = meta.second;
158 RETURN_NOT_OK(buff->write(&value.del_, sizeof(char)));
159 if (!value.del_) {
160 RETURN_NOT_OK(buff->write(&value.type_, sizeof(char)));
161 RETURN_NOT_OK(buff->write(&value.num_, sizeof(uint32_t)));
162 if (value.num_)
163 RETURN_NOT_OK(buff->write(value.value_.data(), value.value_.size()));
164 }
165 }
166
167 return Status::Ok();
168 }
169
timestamp_range() const170 const std::pair<uint64_t, uint64_t>& Metadata::timestamp_range() const {
171 return timestamp_range_;
172 }
173
del(const char * key)174 Status Metadata::del(const char* key) {
175 assert(key != nullptr);
176
177 std::unique_lock<std::mutex> lck(mtx_);
178
179 MetadataValue value;
180 value.del_ = 1;
181 metadata_map_.emplace(std::make_pair(std::string(key), std::move(value)));
182
183 return Status::Ok();
184 }
185
put(const char * key,Datatype value_type,uint32_t value_num,const void * value)186 Status Metadata::put(
187 const char* key,
188 Datatype value_type,
189 uint32_t value_num,
190 const void* value) {
191 assert(key != nullptr);
192 assert(value_type != Datatype::ANY);
193
194 if (value == nullptr)
195 value_num = 0;
196
197 std::unique_lock<std::mutex> lck(mtx_);
198
199 size_t value_size = value_num * datatype_size(value_type);
200 MetadataValue value_struct;
201 value_struct.del_ = 0;
202 value_struct.type_ = static_cast<char>(value_type);
203 value_struct.num_ = value_num;
204 if (value_size) {
205 value_struct.value_.resize(value_size);
206 std::memcpy(value_struct.value_.data(), value, value_size);
207 }
208 metadata_map_.erase(std::string(key));
209 metadata_map_.emplace(
210 std::make_pair(std::string(key), std::move(value_struct)));
211
212 return Status::Ok();
213 }
214
get(const char * key,Datatype * value_type,uint32_t * value_num,const void ** value) const215 Status Metadata::get(
216 const char* key,
217 Datatype* value_type,
218 uint32_t* value_num,
219 const void** value) const {
220 assert(key != nullptr);
221
222 auto it = metadata_map_.find(key);
223 if (it == metadata_map_.end()) {
224 // Key not found
225 *value = nullptr;
226 return Status::Ok();
227 }
228
229 // Key found
230 auto& value_struct = it->second;
231 *value_type = static_cast<Datatype>(value_struct.type_);
232 if (value_struct.num_ == 0) {
233 // zero-valued keys
234 *value_num = 1;
235 *value = nullptr;
236 } else {
237 *value_num = value_struct.num_;
238 *value = (const void*)(value_struct.value_.data());
239 }
240
241 return Status::Ok();
242 }
243
get(uint64_t index,const char ** key,uint32_t * key_len,Datatype * value_type,uint32_t * value_num,const void ** value)244 Status Metadata::get(
245 uint64_t index,
246 const char** key,
247 uint32_t* key_len,
248 Datatype* value_type,
249 uint32_t* value_num,
250 const void** value) {
251 if (metadata_index_.empty())
252 build_metadata_index();
253
254 if (index >= metadata_index_.size())
255 return LOG_STATUS(
256 Status::MetadataError("Cannot get metadata; index out of bounds"));
257
258 // Get key
259 auto& key_str = *(metadata_index_[index].first);
260 *key = key_str.c_str();
261 *key_len = (uint32_t)key_str.size();
262
263 // Get value
264 auto& value_struct = *(metadata_index_[index].second);
265 *value_type = static_cast<Datatype>(value_struct.type_);
266 if (value_struct.num_ == 0) {
267 // zero-valued keys
268 *value_num = 1;
269 *value = nullptr;
270 } else {
271 *value_num = value_struct.num_;
272 *value = (const void*)(value_struct.value_.data());
273 }
274 return Status::Ok();
275 }
276
has_key(const char * key,Datatype * value_type,bool * has_key)277 Status Metadata::has_key(const char* key, Datatype* value_type, bool* has_key) {
278 assert(key != nullptr);
279
280 auto it = metadata_map_.find(key);
281 if (it == metadata_map_.end()) {
282 // Key not found
283 *has_key = false;
284 return Status::Ok();
285 }
286
287 // Key found
288 auto& value_struct = it->second;
289 *value_type = static_cast<Datatype>(value_struct.type_);
290 *has_key = true;
291
292 return Status::Ok();
293 }
294
num() const295 uint64_t Metadata::num() const {
296 return metadata_map_.size();
297 }
298
set_loaded_metadata_uris(const std::vector<TimestampedURI> & loaded_metadata_uris)299 Status Metadata::set_loaded_metadata_uris(
300 const std::vector<TimestampedURI>& loaded_metadata_uris) {
301 if (loaded_metadata_uris.empty())
302 return Status::Ok();
303
304 loaded_metadata_uris_.clear();
305 for (const auto& uri : loaded_metadata_uris)
306 loaded_metadata_uris_.push_back(uri.uri_);
307
308 timestamp_range_.first = loaded_metadata_uris.front().timestamp_range_.first;
309 timestamp_range_.second = loaded_metadata_uris.back().timestamp_range_.second;
310
311 return Status::Ok();
312 }
313
loaded_metadata_uris() const314 const std::vector<URI>& Metadata::loaded_metadata_uris() const {
315 return loaded_metadata_uris_;
316 }
317
swap(Metadata * metadata)318 void Metadata::swap(Metadata* metadata) {
319 std::swap(metadata_map_, metadata->metadata_map_);
320 std::swap(metadata_index_, metadata->metadata_index_);
321 std::swap(timestamp_range_, metadata->timestamp_range_);
322 std::swap(loaded_metadata_uris_, metadata->loaded_metadata_uris_);
323 }
324
reset(uint64_t timestamp)325 void Metadata::reset(uint64_t timestamp) {
326 clear();
327 timestamp = (timestamp != 0) ? timestamp : utils::time::timestamp_now_ms();
328 timestamp_range_ = std::make_pair(timestamp, timestamp);
329 }
330
begin() const331 Metadata::iterator Metadata::begin() const {
332 return metadata_map_.cbegin();
333 }
334
end() const335 Metadata::iterator Metadata::end() const {
336 return metadata_map_.cend();
337 }
338
339 /* ********************************* */
340 /* PRIVATE METHODS */
341 /* ********************************* */
342
build_metadata_index()343 void Metadata::build_metadata_index() {
344 // Create metadata index for fast lookups from index
345 metadata_index_.resize(metadata_map_.size());
346 size_t i = 0;
347 for (auto& m : metadata_map_)
348 metadata_index_[i++] = std::make_pair(&(m.first), &(m.second));
349 }
350
351 } // namespace sm
352 } // namespace tiledb
353