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