Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Move db integrity check to MetadataIntegrityCheck class
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Serong <[email protected]>
  • Loading branch information
tserong committed Nov 3, 2023
1 parent a991a64 commit 2ebb93f
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 36 deletions.
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ set(sources
main.cc
checks.cc
sqlite.cc
checks/metadata_integrity.cc
checks/metadata_schema_version.cc
checks/orphaned_metadata.cc
checks/orphaned_objects.cc
Expand Down
2 changes: 2 additions & 0 deletions src/checks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <utility>
#include <vector>

#include "checks/metadata_integrity.h"
#include "checks/metadata_schema_version.h"
#include "checks/object_integrity.h"
#include "checks/orphaned_metadata.h"
Expand All @@ -43,6 +44,7 @@ bool run_checks(const std::filesystem::path& path, bool should_fix) {
bool all_checks_passed = true;

std::vector<std::shared_ptr<Check>> checks;
checks.emplace_back(std::make_shared<MetadataIntegrityCheck>(path));
checks.emplace_back(std::make_shared<MetadataSchemaVersionCheck>(path));
checks.emplace_back(std::make_shared<OrphanedObjectsCheck>(path));
checks.emplace_back(std::make_shared<OrphanedMetadataCheck>(path));
Expand Down
84 changes: 84 additions & 0 deletions src/checks/metadata_integrity.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2023 SUSE, LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "metadata_integrity.h"

#include <cassert>
#include <cstring>
#include <filesystem>
#include <iostream>
#include <string>

MetadataIntegrityFix::MetadataIntegrityFix(
const std::filesystem::path& path, const std::vector<std::string>& _errors
)
: Fix(path), errors(_errors) {}

void MetadataIntegrityFix::fix() {}

std::string MetadataIntegrityFix::to_string() const {
std::string msg("Database integrity check failed:");
for (auto& s : errors) {
msg += "\n- " + s;
}
return msg;
}

MetadataIntegrityCheck::MetadataIntegrityCheck(const std::filesystem::path& path
)
: Check(FATAL, path) {
metadata = std::make_unique<Database>(root_path / "s3gw.db");
}

MetadataIntegrityCheck::~MetadataIntegrityCheck() {}

bool MetadataIntegrityCheck::check() {
std::vector<std::string> errors;
auto callback = [](void* arg, int num_columns, char** column_data, char**) {
assert(num_columns == 1);
// If this returns anything other than "ok", we'll end up with
// information added to the errors vector, so will know something
// is broken. These are more fine grained than a completely trashed
// database, for example:
// - row 21 missing from index vobjs_object_id_idx
// - non-unique entry in index versioned_object_objid_vid_unique
if (std::strcmp(column_data[0], "ok") != 0) {
static_cast<std::vector<std::string>*>(arg)->emplace_back(column_data[0]);
}
return 0;
};

// This will return up to 100 error rows by default. For more details see
// https://www.sqlite.org/pragma.html#pragma_integrity_check
int rc = sqlite3_exec(
metadata->handle, "PRAGMA integrity_check", callback,
static_cast<void*>(&errors), NULL
);

if (rc != SQLITE_OK) {
// This will happen if the file is _so_ trashed it doesn't even
// look like an SQLite database. Here you'll see things like:
// - file is not a database
// - database disk image is malformed
errors.emplace_back(sqlite3_errstr(rc));
}
if (!errors.empty()) {
fixes.emplace_back(std::make_shared<MetadataIntegrityFix>(root_path, errors)
);
return false;
}
return true;
}
49 changes: 49 additions & 0 deletions src/checks/metadata_integrity.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright 2023 SUSE, LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef FSCK_SFS_SRC_CHECKS_METADATA_INTEGRITY_H__
#define FSCK_SFS_SRC_CHECKS_METADATA_INTEGRITY_H__

#include <filesystem>
#include <memory>

#include "checks.h"
#include "sqlite.h"

class MetadataIntegrityFix : public Fix {
private:
std::string to_string() const;
std::vector<std::string> errors;

public:
MetadataIntegrityFix(
const std::filesystem::path& path, const std::vector<std::string>& _errors
);
operator std::string() const { return to_string(); };
void fix();
};

class MetadataIntegrityCheck : public Check {
private:
std::unique_ptr<Database> metadata;

public:
MetadataIntegrityCheck(const std::filesystem::path& path);
virtual ~MetadataIntegrityCheck() override;
virtual bool check() override;
};

#endif // FSCK_SFS_SRC_CHECKS_METADATA_INTEGRITY_H__
2 changes: 0 additions & 2 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ int main(int argc, char* argv[]) {
std::filesystem::is_regular_file(path_database),
"Metadata database is not a regular file"
);
Database db(path_database);
FSCK_ASSERT(db.check_integrity(), "Database integrity check failed");
}

return run_checks(path_root, options_map.count("fix") > 0) ? 0 : 1;
Expand Down
32 changes: 0 additions & 32 deletions src/sqlite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

#include <sqlite3.h>

#include <cassert>
#include <cstring>
#include <filesystem>
#include <iostream>

Expand All @@ -37,36 +35,6 @@ Database::~Database() {
sqlite3_close(handle);
}

bool Database::check_integrity() {
auto callback = [](void* arg, int num_columns, char** column_data, char**) {
assert(num_columns == 1);
if (std::strcmp(column_data[0], "ok") == 0) {
*(static_cast<bool*>(arg)) = true;
} else {
std::cout << column_data[0] << std::endl;
}
return 0;
};

bool is_ok = false;
// This will return up to 100 error rows by default. For more details see
// https://www.sqlite.org/pragma.html#pragma_integrity_check
int rc = sqlite3_exec(
handle, "PRAGMA integrity_check", callback, static_cast<void*>(&is_ok),
NULL
);
if (rc != SQLITE_OK) {
// This will happen if the file is _so_ trashed it doesn't even
// look like an SQLite database. Here you'll see things like:
// - file is not a database (26)
// - database disk image is malformed (11)
std::cout << "sqlite3_exec error: " << sqlite3_errstr(rc) << " (" << rc
<< ")" << std::endl;
}

return is_ok;
}

int Database::prepare(std::string query, sqlite3_stmt** stm) {
int rc = 0;
const char* unused = 0;
Expand Down
2 changes: 0 additions & 2 deletions src/sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ class Database {
Database(std::filesystem::path);
~Database();

bool check_integrity();

int prepare(std::string, sqlite3_stmt**);

int count_in_table(std::string, std::string);
Expand Down

0 comments on commit 2ebb93f

Please sign in to comment.