sstables: handle unrecognized sstable component

As in C*, unrecognized sstable components should be ignored when
loading a sstable. At the moment, Scylla fails to do so and will
not boot as a result. In addition, unknown components should be
remembered when moving a sstable or changing its generation.

Fixes #1780.

Signed-off-by: Raphael S. Carvalho <raphaelsc@scylladb.com>
Message-Id: <b7af0c28e5b574fd577a7a1d28fb006ac197aa0a.1478025930.git.raphaelsc@scylladb.com>
This commit is contained in:
Raphael S. Carvalho
2016-11-01 16:50:02 -02:00
committed by Avi Kivity
parent 72c2982260
commit 53b7b7def3
12 changed files with 68 additions and 10 deletions

View File

@@ -741,10 +741,10 @@ future<> sstable::read_toc() {
continue;
}
try {
_components.insert(reverse_map(c, _component_map));
_components.insert(reverse_map(c, _component_map));
} catch (std::out_of_range& oor) {
_components.clear(); // so subsequent read_toc will be forced to fail again
throw malformed_sstable_exception("Unrecognized TOC component: " + c, file_path);
_unrecognized_components.push_back(c);
sstlog.info("Unrecognized TOC component was found: {} in sstable {}", c, file_path);
}
}
if (!_components.size()) {
@@ -1958,6 +1958,28 @@ const sstring sstable::filename(sstring dir, sstring ks, sstring cf, version_typ
return dir + "/" + strmap[version](entry_descriptor(ks, cf, version, generation, format, component));
}
const sstring sstable::filename(sstring dir, sstring ks, sstring cf, version_types version, int64_t generation,
format_types format, sstring component) {
static std::unordered_map<version_types, const char*, enum_hash<version_types>> fmtmap = {
{ sstable::version_types::ka, "{0}-{1}-{2}-{3}-{5}" },
{ sstable::version_types::la, "{2}-{3}-{4}-{5}" }
};
return dir + "/" + seastar::format(fmtmap[version], ks, cf, _version_string.at(version), to_sstring(generation), _format_string.at(format), component);
}
std::vector<std::pair<sstable::component_type, sstring>> sstable::all_components() const {
std::vector<std::pair<component_type, sstring>> all;
all.reserve(_components.size() + _unrecognized_components.size());
for (auto& c : _components) {
all.push_back(std::make_pair(c, _component_map.at(c)));
}
for (auto& c : _unrecognized_components) {
all.push_back(std::make_pair(component_type::Unknown, c));
}
return all;
}
future<> sstable::create_links(sstring dir, int64_t generation) const {
// TemporaryTOC is always first, TOC is always last
auto dst = sstable::filename(dir, _schema->ks_name(), _schema->cf_name(), _version, generation, _format, component_type::TemporaryTOC);
@@ -1965,12 +1987,13 @@ future<> sstable::create_links(sstring dir, int64_t generation) const {
return sstable_write_io_check(sync_directory, dir);
}).then([this, dir, generation] {
// FIXME: Should clean already-created links if we failed midway.
return parallel_for_each(_components, [this, dir, generation] (auto comp) {
if (comp == component_type::TOC) {
return parallel_for_each(all_components(), [this, dir, generation] (auto p) {
if (p.first == component_type::TOC) {
return make_ready_future<>();
}
auto dst = sstable::filename(dir, _schema->ks_name(), _schema->cf_name(), _version, generation, _format, comp);
return this->sstable_write_io_check(::link_file, this->filename(comp), dst);
auto src = sstable::filename(_dir, _schema->ks_name(), _schema->cf_name(), _version, _generation, _format, p.second);
auto dst = sstable::filename(dir, _schema->ks_name(), _schema->cf_name(), _version, generation, _format, p.second);
return this->sstable_write_io_check(::link_file, std::move(src), std::move(dst));
});
}).then([this, dir] {
return sstable_write_io_check(sync_directory, dir);
@@ -1990,11 +2013,11 @@ future<> sstable::set_generation(int64_t new_generation) {
return remove_file(filename(component_type::TOC)).then([this] {
return sstable_write_io_check(sync_directory, _dir);
}).then([this] {
return parallel_for_each(_components, [this] (auto comp) {
if (comp == component_type::TOC) {
return parallel_for_each(all_components(), [this] (auto p) {
if (p.first == component_type::TOC) {
return make_ready_future<>();
}
return remove_file(this->filename(comp));
return remove_file(sstable::filename(_dir, _schema->ks_name(), _schema->cf_name(), _version, _generation, _format, p.second));
});
});
}).then([this, new_generation] {

View File

@@ -131,6 +131,7 @@ public:
Statistics,
TemporaryTOC,
TemporaryStatistics,
Unknown,
};
enum class version_types { ka, la };
enum class format_types { big };
@@ -225,6 +226,8 @@ public:
static format_types format_from_sstring(sstring& s);
static const sstring filename(sstring dir, sstring ks, sstring cf, version_types version, int64_t generation,
format_types format, component_type component);
static const sstring filename(sstring dir, sstring ks, sstring cf, version_types version, int64_t generation,
format_types format, sstring component);
// WARNING: it should only be called to remove components of a sstable with
// a temporary TOC file.
static future<> remove_sstable_with_temp_toc(sstring ks, sstring cf, sstring dir, int64_t generation,
@@ -362,6 +365,8 @@ public:
return _collector;
}
std::vector<std::pair<component_type, sstring>> all_components() const;
future<> create_links(sstring dir, int64_t generation) const;
future<> create_links(sstring dir) const {
@@ -405,6 +410,7 @@ private:
static std::unordered_map<component_type, sstring, enum_hash<component_type>> _component_map;
std::unordered_set<component_type, enum_hash<component_type>> _components;
std::vector<sstring> _unrecognized_components;
bool _shared = true; // across shards; safe default
compression _compression;

View File

@@ -3031,3 +3031,22 @@ SEASTAR_TEST_CASE(test_partition_skipping) {
.produces_end_of_stream();
});
}
SEASTAR_TEST_CASE(test_unknown_component) {
return seastar::async([] {
auto tmp = make_lw_shared<tmpdir>();
auto sstp = reusable_sst(uncompressed_schema(), "tests/sstables/unknown_component", 1).get0();
sstp->create_links(tmp->path).get();
// check that create_links() moved unknown component to new dir
BOOST_REQUIRE(file_exists(tmp->path + "/la-1-big-UNKNOWN.txt").get0());
sstp = reusable_sst(uncompressed_schema(), tmp->path, 1).get0();
sstp->set_generation(2).get();
BOOST_REQUIRE(!file_exists(tmp->path + "/la-1-big-UNKNOWN.txt").get0());
BOOST_REQUIRE(file_exists(tmp->path + "/la-2-big-UNKNOWN.txt").get0());
sstables::delete_atomically({sstp}).get();
// assure unknown component is deleted
BOOST_REQUIRE(!file_exists(tmp->path + "/la-2-big-UNKNOWN.txt").get0());
});
}

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
748507322

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,9 @@
Data.db
Filter.db
CRC.db
Statistics.db
Summary.db
Digest.sha1
Index.db
TOC.txt
UNKNOWN.txt