1 /**
2 * @file array_schema_evolution.cc
3 *
4 * @section LICENSE
5 *
6 * The MIT License
7 *
8 * @copyright Copyright (c) 2018-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 defines serialization functions for ArraySchemaEvolution.
31 */
32 #ifdef TILEDB_SERIALIZATION
33 #include <capnp/compat/json.h>
34 #include <capnp/serialize.h>
35 #include "tiledb/sm/serialization/capnp_utils.h"
36 #endif
37
38 #include "tiledb/common/heap_memory.h"
39 #include "tiledb/common/logger.h"
40 #include "tiledb/sm/array/array.h"
41 #include "tiledb/sm/array_schema/array_schema_evolution.h"
42 #include "tiledb/sm/array_schema/attribute.h"
43 #include "tiledb/sm/array_schema/dimension.h"
44 #include "tiledb/sm/array_schema/domain.h"
45 #include "tiledb/sm/enums/array_type.h"
46 #include "tiledb/sm/enums/compressor.h"
47 #include "tiledb/sm/enums/datatype.h"
48 #include "tiledb/sm/enums/filter_option.h"
49 #include "tiledb/sm/enums/filter_type.h"
50 #include "tiledb/sm/enums/layout.h"
51 #include "tiledb/sm/enums/serialization_type.h"
52 #include "tiledb/sm/misc/constants.h"
53 #include "tiledb/sm/serialization/array_schema.h"
54
55 #include <set>
56
57 using namespace tiledb::common;
58
59 namespace tiledb {
60 namespace sm {
61 namespace serialization {
62
63 #ifdef TILEDB_SERIALIZATION
64
array_schema_evolution_to_capnp(const ArraySchemaEvolution * array_schema_evolution,capnp::ArraySchemaEvolution::Builder * array_schema_evolution_builder,const bool client_side)65 Status array_schema_evolution_to_capnp(
66 const ArraySchemaEvolution* array_schema_evolution,
67 capnp::ArraySchemaEvolution::Builder* array_schema_evolution_builder,
68 const bool client_side) {
69 if (array_schema_evolution == nullptr)
70 return LOG_STATUS(
71 Status::SerializationError("Error serializing array schema evolution; "
72 "array schema evolution is null."));
73
74 // Attributes to drop
75 std::vector<std::string> attr_names_to_drop =
76 array_schema_evolution->attribute_names_to_drop();
77
78 auto attributes_to_drop_builder =
79 array_schema_evolution_builder->initAttributesToDrop(
80 attr_names_to_drop.size());
81
82 for (size_t i = 0; i < attr_names_to_drop.size(); i++) {
83 attributes_to_drop_builder.set(i, attr_names_to_drop[i]);
84 }
85
86 // Attributes to add
87 std::vector<std::string> attr_names_to_add =
88 array_schema_evolution->attribute_names_to_add();
89
90 auto attributes_to_add_buidler =
91 array_schema_evolution_builder->initAttributesToAdd(
92 attr_names_to_add.size());
93
94 for (size_t i = 0; i < attr_names_to_add.size(); i++) {
95 auto attribute_builder = attributes_to_add_buidler[i];
96 auto attr_name = attr_names_to_add[i];
97 const Attribute* attr_to_add =
98 array_schema_evolution->attribute_to_add(attr_name);
99 if (attr_to_add == nullptr) {
100 continue;
101 }
102 RETURN_NOT_OK(attribute_to_capnp(attr_to_add, &attribute_builder));
103 }
104
105 return Status::Ok();
106 }
107
array_schema_evolution_from_capnp(const capnp::ArraySchemaEvolution::Reader & evolution_reader,tdb_unique_ptr<ArraySchemaEvolution> * array_schema_evolution)108 Status array_schema_evolution_from_capnp(
109 const capnp::ArraySchemaEvolution::Reader& evolution_reader,
110 tdb_unique_ptr<ArraySchemaEvolution>* array_schema_evolution) {
111 array_schema_evolution->reset(tdb_new(ArraySchemaEvolution));
112 // Set attributes to drop
113 auto attributes_to_drop_reader = evolution_reader.getAttributesToDrop();
114 for (auto attr_reader : attributes_to_drop_reader) {
115 std::string attr_name = std::string(attr_reader.cStr());
116 RETURN_NOT_OK((*array_schema_evolution)->drop_attribute(attr_name));
117 }
118
119 // Set attributes to add
120 auto attributes_to_add_reader = evolution_reader.getAttributesToAdd();
121 for (auto attr_reader : attributes_to_add_reader) {
122 tdb_unique_ptr<Attribute> attribute;
123 RETURN_NOT_OK(attribute_from_capnp(attr_reader, &attribute));
124 const Attribute* attr_to_add = attribute.get();
125 RETURN_NOT_OK((*array_schema_evolution)->add_attribute(attr_to_add));
126 }
127
128 return Status::Ok();
129 }
130
array_schema_evolution_serialize(ArraySchemaEvolution * array_schema_evolution,SerializationType serialize_type,Buffer * serialized_buffer,const bool client_side)131 Status array_schema_evolution_serialize(
132 ArraySchemaEvolution* array_schema_evolution,
133 SerializationType serialize_type,
134 Buffer* serialized_buffer,
135 const bool client_side) {
136 try {
137 ::capnp::MallocMessageBuilder message;
138 capnp::ArraySchemaEvolution::Builder arraySchemaEvolutionBuilder =
139 message.initRoot<capnp::ArraySchemaEvolution>();
140 RETURN_NOT_OK(array_schema_evolution_to_capnp(
141 array_schema_evolution, &arraySchemaEvolutionBuilder, client_side));
142
143 serialized_buffer->reset_size();
144 serialized_buffer->reset_offset();
145
146 switch (serialize_type) {
147 case SerializationType::JSON: {
148 ::capnp::JsonCodec json;
149 kj::String capnp_json = json.encode(arraySchemaEvolutionBuilder);
150 const auto json_len = capnp_json.size();
151 const char nul = '\0';
152 // size does not include needed null terminator, so add +1
153 RETURN_NOT_OK(serialized_buffer->realloc(json_len + 1));
154 RETURN_NOT_OK(serialized_buffer->write(capnp_json.cStr(), json_len));
155 RETURN_NOT_OK(serialized_buffer->write(&nul, 1));
156 break;
157 }
158 case SerializationType::CAPNP: {
159 kj::Array<::capnp::word> protomessage = messageToFlatArray(message);
160 kj::ArrayPtr<const char> message_chars = protomessage.asChars();
161 const auto nbytes = message_chars.size();
162 RETURN_NOT_OK(serialized_buffer->realloc(nbytes));
163 RETURN_NOT_OK(serialized_buffer->write(message_chars.begin(), nbytes));
164 break;
165 }
166 default: {
167 return LOG_STATUS(
168 Status::SerializationError("Error serializing array schema "
169 "evolution; Unknown serialization type "
170 "passed"));
171 }
172 }
173
174 } catch (kj::Exception& e) {
175 return LOG_STATUS(Status::SerializationError(
176 "Error serializing array schema evolution; kj::Exception: " +
177 std::string(e.getDescription().cStr())));
178 } catch (std::exception& e) {
179 return LOG_STATUS(Status::SerializationError(
180 "Error serializing array schema evolution; exception " +
181 std::string(e.what())));
182 }
183
184 return Status::Ok();
185 }
186
array_schema_evolution_deserialize(ArraySchemaEvolution ** array_schema_evolution,SerializationType serialize_type,const Buffer & serialized_buffer)187 Status array_schema_evolution_deserialize(
188 ArraySchemaEvolution** array_schema_evolution,
189 SerializationType serialize_type,
190 const Buffer& serialized_buffer) {
191 try {
192 tdb_unique_ptr<ArraySchemaEvolution> decoded_array_schema_evolution =
193 nullptr;
194
195 switch (serialize_type) {
196 case SerializationType::JSON: {
197 ::capnp::JsonCodec json;
198 ::capnp::MallocMessageBuilder message_builder;
199 capnp::ArraySchemaEvolution::Builder array_schema_evolution_builder =
200 message_builder.initRoot<capnp::ArraySchemaEvolution>();
201 json.decode(
202 kj::StringPtr(static_cast<const char*>(serialized_buffer.data())),
203 array_schema_evolution_builder);
204 capnp::ArraySchemaEvolution::Reader array_schema_evolution_reader =
205 array_schema_evolution_builder.asReader();
206 RETURN_NOT_OK(array_schema_evolution_from_capnp(
207 array_schema_evolution_reader, &decoded_array_schema_evolution));
208 break;
209 }
210 case SerializationType::CAPNP: {
211 const auto mBytes =
212 reinterpret_cast<const kj::byte*>(serialized_buffer.data());
213 ::capnp::FlatArrayMessageReader reader(kj::arrayPtr(
214 reinterpret_cast<const ::capnp::word*>(mBytes),
215 serialized_buffer.size() / sizeof(::capnp::word)));
216 capnp::ArraySchemaEvolution::Reader array_schema_evolution_reader =
217 reader.getRoot<capnp::ArraySchemaEvolution>();
218 RETURN_NOT_OK(array_schema_evolution_from_capnp(
219 array_schema_evolution_reader, &decoded_array_schema_evolution));
220 break;
221 }
222 default: {
223 return LOG_STATUS(
224 Status::SerializationError("Error deserializing array schema "
225 "evolution; Unknown serialization type "
226 "passed"));
227 }
228 }
229
230 if (decoded_array_schema_evolution == nullptr)
231 return LOG_STATUS(Status::SerializationError(
232 "Error serializing array schema evolution; deserialized schema "
233 "evolution is null"));
234
235 *array_schema_evolution = decoded_array_schema_evolution.release();
236 } catch (kj::Exception& e) {
237 return LOG_STATUS(Status::SerializationError(
238 "Error deserializing array schema evolution; kj::Exception: " +
239 std::string(e.getDescription().cStr())));
240 } catch (std::exception& e) {
241 return LOG_STATUS(Status::SerializationError(
242 "Error deserializing array schema evolution; exception " +
243 std::string(e.what())));
244 }
245
246 return Status::Ok();
247 }
248
249 #else
250
251 Status array_schema_evolution_serialize(
252 ArraySchemaEvolution*, SerializationType, Buffer*, const bool) {
253 return LOG_STATUS(Status::SerializationError(
254 "Cannot serialize; serialization not enabled."));
255 }
256
257 Status array_schema_evolution_deserialize(
258 ArraySchemaEvolution**, SerializationType, const Buffer&) {
259 return LOG_STATUS(Status::SerializationError(
260 "Cannot serialize; serialization not enabled."));
261 }
262
263 #endif // TILEDB_SERIALIZATION
264
265 } // namespace serialization
266 } // namespace sm
267 } // namespace tiledb