]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/utilities/option_change_migration/option_change_migration_test.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / utilities / option_change_migration / option_change_migration_test.cc
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10 #include "rocksdb/utilities/option_change_migration.h"
11
12 #include <set>
13
14 #include "db/db_test_util.h"
15 #include "port/stack_trace.h"
16 #include "util/random.h"
17
18 namespace ROCKSDB_NAMESPACE {
19
20 class DBOptionChangeMigrationTests
21 : public DBTestBase,
22 public testing::WithParamInterface<
23 std::tuple<int, int, bool, int, int, bool, uint64_t>> {
24 public:
25 DBOptionChangeMigrationTests()
26 : DBTestBase("db_option_change_migration_test", /*env_do_fsync=*/true) {
27 level1_ = std::get<0>(GetParam());
28 compaction_style1_ = std::get<1>(GetParam());
29 is_dynamic1_ = std::get<2>(GetParam());
30
31 level2_ = std::get<3>(GetParam());
32 compaction_style2_ = std::get<4>(GetParam());
33 is_dynamic2_ = std::get<5>(GetParam());
34 fifo_max_table_files_size_ = std::get<6>(GetParam());
35 }
36
37 // Required if inheriting from testing::WithParamInterface<>
38 static void SetUpTestCase() {}
39 static void TearDownTestCase() {}
40
41 int level1_;
42 int compaction_style1_;
43 bool is_dynamic1_;
44
45 int level2_;
46 int compaction_style2_;
47 bool is_dynamic2_;
48
49 uint64_t fifo_max_table_files_size_;
50 };
51
52 #ifndef ROCKSDB_LITE
53 TEST_P(DBOptionChangeMigrationTests, Migrate1) {
54 Options old_options = CurrentOptions();
55 old_options.compaction_style =
56 static_cast<CompactionStyle>(compaction_style1_);
57 if (old_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
58 old_options.level_compaction_dynamic_level_bytes = is_dynamic1_;
59 }
60 if (old_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
61 old_options.max_open_files = -1;
62 }
63 old_options.level0_file_num_compaction_trigger = 3;
64 old_options.write_buffer_size = 64 * 1024;
65 old_options.target_file_size_base = 128 * 1024;
66 // Make level target of L1, L2 to be 200KB and 600KB
67 old_options.num_levels = level1_;
68 old_options.max_bytes_for_level_multiplier = 3;
69 old_options.max_bytes_for_level_base = 200 * 1024;
70
71 Reopen(old_options);
72
73 Random rnd(301);
74 int key_idx = 0;
75
76 // Generate at least 2MB of data
77 for (int num = 0; num < 20; num++) {
78 GenerateNewFile(&rnd, &key_idx);
79 }
80 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
81 ASSERT_OK(dbfull()->TEST_WaitForCompact());
82
83 // Will make sure exactly those keys are in the DB after migration.
84 std::set<std::string> keys;
85 {
86 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
87 it->SeekToFirst();
88 for (; it->Valid(); it->Next()) {
89 keys.insert(it->key().ToString());
90 }
91 }
92 Close();
93
94 Options new_options = old_options;
95 new_options.compaction_style =
96 static_cast<CompactionStyle>(compaction_style2_);
97 if (new_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
98 new_options.level_compaction_dynamic_level_bytes = is_dynamic2_;
99 }
100 if (new_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
101 new_options.max_open_files = -1;
102 }
103 if (fifo_max_table_files_size_ != 0) {
104 new_options.compaction_options_fifo.max_table_files_size =
105 fifo_max_table_files_size_;
106 }
107 new_options.target_file_size_base = 256 * 1024;
108 new_options.num_levels = level2_;
109 new_options.max_bytes_for_level_base = 150 * 1024;
110 new_options.max_bytes_for_level_multiplier = 4;
111 ASSERT_OK(OptionChangeMigration(dbname_, old_options, new_options));
112 Reopen(new_options);
113
114 // Wait for compaction to finish and make sure it can reopen
115 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
116 ASSERT_OK(dbfull()->TEST_WaitForCompact());
117 Reopen(new_options);
118
119 {
120 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
121 it->SeekToFirst();
122 for (std::string key : keys) {
123 ASSERT_TRUE(it->Valid());
124 ASSERT_EQ(key, it->key().ToString());
125 it->Next();
126 }
127 ASSERT_TRUE(!it->Valid());
128 }
129 }
130
131 TEST_P(DBOptionChangeMigrationTests, Migrate2) {
132 Options old_options = CurrentOptions();
133 old_options.compaction_style =
134 static_cast<CompactionStyle>(compaction_style2_);
135 if (old_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
136 old_options.level_compaction_dynamic_level_bytes = is_dynamic2_;
137 }
138 if (old_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
139 old_options.max_open_files = -1;
140 }
141 old_options.level0_file_num_compaction_trigger = 3;
142 old_options.write_buffer_size = 64 * 1024;
143 old_options.target_file_size_base = 128 * 1024;
144 // Make level target of L1, L2 to be 200KB and 600KB
145 old_options.num_levels = level2_;
146 old_options.max_bytes_for_level_multiplier = 3;
147 old_options.max_bytes_for_level_base = 200 * 1024;
148
149 Reopen(old_options);
150
151 Random rnd(301);
152 int key_idx = 0;
153
154 // Generate at least 2MB of data
155 for (int num = 0; num < 20; num++) {
156 GenerateNewFile(&rnd, &key_idx);
157 }
158 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
159 ASSERT_OK(dbfull()->TEST_WaitForCompact());
160
161 // Will make sure exactly those keys are in the DB after migration.
162 std::set<std::string> keys;
163 {
164 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
165 it->SeekToFirst();
166 for (; it->Valid(); it->Next()) {
167 keys.insert(it->key().ToString());
168 }
169 }
170
171 Close();
172
173 Options new_options = old_options;
174 new_options.compaction_style =
175 static_cast<CompactionStyle>(compaction_style1_);
176 if (new_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
177 new_options.level_compaction_dynamic_level_bytes = is_dynamic1_;
178 }
179 if (new_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
180 new_options.max_open_files = -1;
181 }
182 if (fifo_max_table_files_size_ != 0) {
183 new_options.compaction_options_fifo.max_table_files_size =
184 fifo_max_table_files_size_;
185 }
186 new_options.target_file_size_base = 256 * 1024;
187 new_options.num_levels = level1_;
188 new_options.max_bytes_for_level_base = 150 * 1024;
189 new_options.max_bytes_for_level_multiplier = 4;
190 ASSERT_OK(OptionChangeMigration(dbname_, old_options, new_options));
191 Reopen(new_options);
192 // Wait for compaction to finish and make sure it can reopen
193 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
194 ASSERT_OK(dbfull()->TEST_WaitForCompact());
195 Reopen(new_options);
196
197 {
198 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
199 it->SeekToFirst();
200 for (std::string key : keys) {
201 ASSERT_TRUE(it->Valid());
202 ASSERT_EQ(key, it->key().ToString());
203 it->Next();
204 }
205 ASSERT_TRUE(!it->Valid());
206 }
207 }
208
209 TEST_P(DBOptionChangeMigrationTests, Migrate3) {
210 Options old_options = CurrentOptions();
211 old_options.compaction_style =
212 static_cast<CompactionStyle>(compaction_style1_);
213 if (old_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
214 old_options.level_compaction_dynamic_level_bytes = is_dynamic1_;
215 }
216 if (old_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
217 old_options.max_open_files = -1;
218 }
219 old_options.level0_file_num_compaction_trigger = 3;
220 old_options.write_buffer_size = 64 * 1024;
221 old_options.target_file_size_base = 128 * 1024;
222 // Make level target of L1, L2 to be 200KB and 600KB
223 old_options.num_levels = level1_;
224 old_options.max_bytes_for_level_multiplier = 3;
225 old_options.max_bytes_for_level_base = 200 * 1024;
226
227 Reopen(old_options);
228 Random rnd(301);
229 for (int num = 0; num < 20; num++) {
230 for (int i = 0; i < 50; i++) {
231 ASSERT_OK(Put(Key(num * 100 + i), rnd.RandomString(900)));
232 }
233 Flush();
234 ASSERT_OK(dbfull()->TEST_WaitForCompact());
235 if (num == 9) {
236 // Issue a full compaction to generate some zero-out files
237 CompactRangeOptions cro;
238 cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
239 ASSERT_OK(dbfull()->CompactRange(cro, nullptr, nullptr));
240 }
241 }
242 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
243 ASSERT_OK(dbfull()->TEST_WaitForCompact());
244
245 // Will make sure exactly those keys are in the DB after migration.
246 std::set<std::string> keys;
247 {
248 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
249 it->SeekToFirst();
250 for (; it->Valid(); it->Next()) {
251 keys.insert(it->key().ToString());
252 }
253 }
254 Close();
255
256 Options new_options = old_options;
257 new_options.compaction_style =
258 static_cast<CompactionStyle>(compaction_style2_);
259 if (new_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
260 new_options.level_compaction_dynamic_level_bytes = is_dynamic2_;
261 }
262 if (new_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
263 new_options.max_open_files = -1;
264 }
265 if (fifo_max_table_files_size_ != 0) {
266 new_options.compaction_options_fifo.max_table_files_size =
267 fifo_max_table_files_size_;
268 }
269 new_options.target_file_size_base = 256 * 1024;
270 new_options.num_levels = level2_;
271 new_options.max_bytes_for_level_base = 150 * 1024;
272 new_options.max_bytes_for_level_multiplier = 4;
273 ASSERT_OK(OptionChangeMigration(dbname_, old_options, new_options));
274 Reopen(new_options);
275
276 // Wait for compaction to finish and make sure it can reopen
277 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
278 ASSERT_OK(dbfull()->TEST_WaitForCompact());
279 Reopen(new_options);
280
281 {
282 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
283 it->SeekToFirst();
284 for (std::string key : keys) {
285 ASSERT_TRUE(it->Valid());
286 ASSERT_EQ(key, it->key().ToString());
287 it->Next();
288 }
289 ASSERT_TRUE(!it->Valid());
290 }
291 }
292
293 TEST_P(DBOptionChangeMigrationTests, Migrate4) {
294 Options old_options = CurrentOptions();
295 old_options.compaction_style =
296 static_cast<CompactionStyle>(compaction_style2_);
297 if (old_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
298 old_options.level_compaction_dynamic_level_bytes = is_dynamic2_;
299 }
300 if (old_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
301 old_options.max_open_files = -1;
302 }
303 old_options.level0_file_num_compaction_trigger = 3;
304 old_options.write_buffer_size = 64 * 1024;
305 old_options.target_file_size_base = 128 * 1024;
306 // Make level target of L1, L2 to be 200KB and 600KB
307 old_options.num_levels = level2_;
308 old_options.max_bytes_for_level_multiplier = 3;
309 old_options.max_bytes_for_level_base = 200 * 1024;
310
311 Reopen(old_options);
312 Random rnd(301);
313 for (int num = 0; num < 20; num++) {
314 for (int i = 0; i < 50; i++) {
315 ASSERT_OK(Put(Key(num * 100 + i), rnd.RandomString(900)));
316 }
317 Flush();
318 ASSERT_OK(dbfull()->TEST_WaitForCompact());
319 if (num == 9) {
320 // Issue a full compaction to generate some zero-out files
321 CompactRangeOptions cro;
322 cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
323 ASSERT_OK(dbfull()->CompactRange(cro, nullptr, nullptr));
324 }
325 }
326 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
327 ASSERT_OK(dbfull()->TEST_WaitForCompact());
328
329 // Will make sure exactly those keys are in the DB after migration.
330 std::set<std::string> keys;
331 {
332 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
333 it->SeekToFirst();
334 for (; it->Valid(); it->Next()) {
335 keys.insert(it->key().ToString());
336 }
337 }
338
339 Close();
340
341 Options new_options = old_options;
342 new_options.compaction_style =
343 static_cast<CompactionStyle>(compaction_style1_);
344 if (new_options.compaction_style == CompactionStyle::kCompactionStyleLevel) {
345 new_options.level_compaction_dynamic_level_bytes = is_dynamic1_;
346 }
347 if (new_options.compaction_style == CompactionStyle::kCompactionStyleFIFO) {
348 new_options.max_open_files = -1;
349 }
350 if (fifo_max_table_files_size_ != 0) {
351 new_options.compaction_options_fifo.max_table_files_size =
352 fifo_max_table_files_size_;
353 }
354 new_options.target_file_size_base = 256 * 1024;
355 new_options.num_levels = level1_;
356 new_options.max_bytes_for_level_base = 150 * 1024;
357 new_options.max_bytes_for_level_multiplier = 4;
358 ASSERT_OK(OptionChangeMigration(dbname_, old_options, new_options));
359 Reopen(new_options);
360 // Wait for compaction to finish and make sure it can reopen
361 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
362 ASSERT_OK(dbfull()->TEST_WaitForCompact());
363 Reopen(new_options);
364
365 {
366 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
367 it->SeekToFirst();
368 for (std::string key : keys) {
369 ASSERT_TRUE(it->Valid());
370 ASSERT_EQ(key, it->key().ToString());
371 it->Next();
372 }
373 ASSERT_TRUE(!it->Valid());
374 }
375 }
376
377 INSTANTIATE_TEST_CASE_P(
378 DBOptionChangeMigrationTests, DBOptionChangeMigrationTests,
379 ::testing::Values(
380 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
381 false /* is dynamic leveling in old option */,
382 4 /* old num_levels */, 0 /* new compaction style */,
383 false /* is dynamic leveling in new option */,
384 0 /*fifo max_table_files_size*/),
385 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
386 true /* is dynamic leveling in old option */,
387 4 /* old num_levels */, 0 /* new compaction style */,
388 true /* is dynamic leveling in new option */,
389 0 /*fifo max_table_files_size*/),
390 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
391 true /* is dynamic leveling in old option */,
392 4 /* old num_levels */, 0 /* new compaction style */,
393 false, 0 /*fifo max_table_files_size*/),
394 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
395 false /* is dynamic leveling in old option */,
396 4 /* old num_levels */, 0 /* new compaction style */,
397 true /* is dynamic leveling in new option */,
398 0 /*fifo max_table_files_size*/),
399 std::make_tuple(3 /* old num_levels */, 1 /* old compaction style */,
400 false /* is dynamic leveling in old option */,
401 4 /* old num_levels */, 1 /* new compaction style */,
402 false /* is dynamic leveling in new option */,
403 0 /*fifo max_table_files_size*/),
404 std::make_tuple(1 /* old num_levels */, 1 /* old compaction style */,
405 false /* is dynamic leveling in old option */,
406 4 /* old num_levels */, 1 /* new compaction style */,
407 false /* is dynamic leveling in new option */,
408 0 /*fifo max_table_files_size*/),
409 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
410 false /* is dynamic leveling in old option */,
411 4 /* old num_levels */, 1 /* new compaction style */,
412 false /* is dynamic leveling in new option */,
413 0 /*fifo max_table_files_size*/),
414 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
415 false /* is dynamic leveling in old option */,
416 1 /* old num_levels */, 1 /* new compaction style */,
417 false /* is dynamic leveling in new option */,
418 0 /*fifo max_table_files_size*/),
419 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
420 true /* is dynamic leveling in old option */,
421 4 /* old num_levels */, 1 /* new compaction style */,
422 false /* is dynamic leveling in new option */,
423 0 /*fifo max_table_files_size*/),
424 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
425 true /* is dynamic leveling in old option */,
426 1 /* old num_levels */, 1 /* new compaction style */,
427 false /* is dynamic leveling in new option */,
428 0 /*fifo max_table_files_size*/),
429 std::make_tuple(1 /* old num_levels */, 1 /* old compaction style */,
430 false /* is dynamic leveling in old option */,
431 4 /* old num_levels */, 0 /* new compaction style */,
432 false /* is dynamic leveling in new option */,
433 0 /*fifo max_table_files_size*/),
434 std::make_tuple(4 /* old num_levels */, 0 /* old compaction style */,
435 false /* is dynamic leveling in old option */,
436 1 /* old num_levels */, 2 /* new compaction style */,
437 false /* is dynamic leveling in new option */,
438 0 /*fifo max_table_files_size*/),
439 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
440 true /* is dynamic leveling in old option */,
441 2 /* old num_levels */, 2 /* new compaction style */,
442 false /* is dynamic leveling in new option */,
443 0 /*fifo max_table_files_size*/),
444 std::make_tuple(3 /* old num_levels */, 1 /* old compaction style */,
445 false /* is dynamic leveling in old option */,
446 3 /* old num_levels */, 2 /* new compaction style */,
447 false /* is dynamic leveling in new option */,
448 0 /*fifo max_table_files_size*/),
449 std::make_tuple(1 /* old num_levels */, 1 /* old compaction style */,
450 false /* is dynamic leveling in old option */,
451 4 /* old num_levels */, 2 /* new compaction style */,
452 false /* is dynamic leveling in new option */, 0),
453 std::make_tuple(4 /* old num_levels */, 0 /* old compaction style */,
454 false /* is dynamic leveling in old option */,
455 1 /* old num_levels */, 2 /* new compaction style */,
456 false /* is dynamic leveling in new option */,
457 5 * 1024 * 1024 /*fifo max_table_files_size*/),
458 std::make_tuple(3 /* old num_levels */, 0 /* old compaction style */,
459 true /* is dynamic leveling in old option */,
460 2 /* old num_levels */, 2 /* new compaction style */,
461 false /* is dynamic leveling in new option */,
462 5 * 1024 * 1024 /*fifo max_table_files_size*/),
463 std::make_tuple(3 /* old num_levels */, 1 /* old compaction style */,
464 false /* is dynamic leveling in old option */,
465 3 /* old num_levels */, 2 /* new compaction style */,
466 false /* is dynamic leveling in new option */,
467 5 * 1024 * 1024 /*fifo max_table_files_size*/),
468 std::make_tuple(1 /* old num_levels */, 1 /* old compaction style */,
469 false /* is dynamic leveling in old option */,
470 4 /* old num_levels */, 2 /* new compaction style */,
471 false /* is dynamic leveling in new option */,
472 5 * 1024 * 1024 /*fifo max_table_files_size*/)));
473
474 class DBOptionChangeMigrationTest : public DBTestBase {
475 public:
476 DBOptionChangeMigrationTest()
477 : DBTestBase("db_option_change_migration_test2", /*env_do_fsync=*/true) {}
478 };
479
480 TEST_F(DBOptionChangeMigrationTest, CompactedSrcToUniversal) {
481 Options old_options = CurrentOptions();
482 old_options.compaction_style = CompactionStyle::kCompactionStyleLevel;
483 old_options.max_compaction_bytes = 200 * 1024;
484 old_options.level_compaction_dynamic_level_bytes = false;
485 old_options.level0_file_num_compaction_trigger = 3;
486 old_options.write_buffer_size = 64 * 1024;
487 old_options.target_file_size_base = 128 * 1024;
488 // Make level target of L1, L2 to be 200KB and 600KB
489 old_options.num_levels = 4;
490 old_options.max_bytes_for_level_multiplier = 3;
491 old_options.max_bytes_for_level_base = 200 * 1024;
492
493 Reopen(old_options);
494 Random rnd(301);
495 for (int num = 0; num < 20; num++) {
496 for (int i = 0; i < 50; i++) {
497 ASSERT_OK(Put(Key(num * 100 + i), rnd.RandomString(900)));
498 }
499 }
500 Flush();
501 CompactRangeOptions cro;
502 cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
503 ASSERT_OK(dbfull()->CompactRange(cro, nullptr, nullptr));
504
505 // Will make sure exactly those keys are in the DB after migration.
506 std::set<std::string> keys;
507 {
508 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
509 it->SeekToFirst();
510 for (; it->Valid(); it->Next()) {
511 keys.insert(it->key().ToString());
512 }
513 }
514
515 Close();
516
517 Options new_options = old_options;
518 new_options.compaction_style = CompactionStyle::kCompactionStyleUniversal;
519 new_options.target_file_size_base = 256 * 1024;
520 new_options.num_levels = 1;
521 new_options.max_bytes_for_level_base = 150 * 1024;
522 new_options.max_bytes_for_level_multiplier = 4;
523 ASSERT_OK(OptionChangeMigration(dbname_, old_options, new_options));
524 Reopen(new_options);
525 // Wait for compaction to finish and make sure it can reopen
526 ASSERT_OK(dbfull()->TEST_WaitForFlushMemTable());
527 ASSERT_OK(dbfull()->TEST_WaitForCompact());
528 Reopen(new_options);
529
530 {
531 std::unique_ptr<Iterator> it(db_->NewIterator(ReadOptions()));
532 it->SeekToFirst();
533 for (std::string key : keys) {
534 ASSERT_TRUE(it->Valid());
535 ASSERT_EQ(key, it->key().ToString());
536 it->Next();
537 }
538 ASSERT_TRUE(!it->Valid());
539 ASSERT_OK(it->status());
540 }
541 }
542
543 #endif // ROCKSDB_LITE
544 } // namespace ROCKSDB_NAMESPACE
545
546 int main(int argc, char** argv) {
547 ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
548 ::testing::InitGoogleTest(&argc, argv);
549 return RUN_ALL_TESTS();
550 }