mirror of
https://github.com/facebook/sapling.git
synced 2024-10-05 14:28:17 +03:00
sqlite: split Sqlite.h
Summary: This diff splits Sqlite.h into smaller files so it's easier to change. Reviewed By: xavierd Differential Revision: D26656315 fbshipit-source-id: 8156b1d8feef47e5bad4ab66ad5f5f96cf32547e
This commit is contained in:
parent
1651dd1898
commit
6162023789
@ -14,7 +14,7 @@
|
||||
#include <thrift/lib/cpp2/protocol/Serializer.h>
|
||||
#include <iostream>
|
||||
#include "eden/fs/inodes/InodeNumber.h"
|
||||
#include "eden/fs/sqlite/Sqlite.h"
|
||||
#include "eden/fs/sqlite/SqliteStatement.h"
|
||||
#include "eden/fs/store/StoreResult.h"
|
||||
#include "eden/fs/utils/Bug.h"
|
||||
#include "eden/fs/utils/PathFuncs.h"
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "eden/fs/inodes/IOverlay.h"
|
||||
#include "eden/fs/inodes/overlay/gen-cpp2/overlay_types.h"
|
||||
#include "eden/fs/sqlite/Sqlite.h"
|
||||
#include "eden/fs/sqlite/SqliteDatabase.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace eden {
|
||||
|
@ -12,7 +12,8 @@
|
||||
#include <memory>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "eden/fs/sqlite/Sqlite.h"
|
||||
#include "eden/fs/sqlite/SqliteDatabase.h"
|
||||
#include "eden/fs/sqlite/SqliteStatement.h"
|
||||
#include "eden/fs/utils/PathFuncs.h"
|
||||
|
||||
struct sqlite3;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "eden/fs/inodes/InodeNumber.h"
|
||||
#include "eden/fs/inodes/overlay/gen-cpp2/overlay_types.h"
|
||||
#include "eden/fs/model/Hash.h"
|
||||
#include "eden/fs/sqlite/Sqlite.h"
|
||||
#include "eden/fs/sqlite/SqliteDatabase.h"
|
||||
#include "eden/fs/utils/DirType.h"
|
||||
#include "eden/fs/utils/PathFuncs.h"
|
||||
|
||||
|
76
eden/fs/sqlite/SqliteDatabase.cpp
Normal file
76
eden/fs/sqlite/SqliteDatabase.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This software may be used and distributed according to the terms of the
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include "eden/fs/sqlite/SqliteDatabase.h"
|
||||
|
||||
#include <folly/logging/xlog.h>
|
||||
#include "eden/fs/sqlite/SqliteStatement.h"
|
||||
|
||||
namespace facebook::eden {
|
||||
void checkSqliteResult(sqlite3* db, int result) {
|
||||
if (result == SQLITE_OK) {
|
||||
return;
|
||||
}
|
||||
// Sometimes the db instance holds more useful context
|
||||
if (db) {
|
||||
auto error = fmt::format(
|
||||
"sqlite error ({}): {} {}",
|
||||
result,
|
||||
sqlite3_errstr(result),
|
||||
sqlite3_errmsg(db));
|
||||
XLOG(DBG6) << error;
|
||||
throw std::runtime_error(error);
|
||||
} else {
|
||||
// otherwise resort to a simpler number->string mapping
|
||||
auto error =
|
||||
fmt::format("sqlite error ({}): {}", result, sqlite3_errstr(result));
|
||||
XLOG(DBG6) << error;
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
SqliteDatabase::SqliteDatabase(const char* addr) {
|
||||
sqlite3* db = nullptr;
|
||||
auto result = sqlite3_open(addr, &db);
|
||||
if (result != SQLITE_OK) {
|
||||
// sqlite3_close handles nullptr fine
|
||||
// @lint-ignore CLANGTIDY
|
||||
sqlite3_close(db);
|
||||
checkSqliteResult(nullptr, result);
|
||||
}
|
||||
db_ = db;
|
||||
}
|
||||
|
||||
void SqliteDatabase::close() {
|
||||
auto db = db_.wlock();
|
||||
if (*db) {
|
||||
sqlite3_close(*db);
|
||||
*db = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SqliteDatabase::~SqliteDatabase() {
|
||||
close();
|
||||
}
|
||||
|
||||
SqliteDatabase::Connection SqliteDatabase::lock() {
|
||||
return db_.wlock();
|
||||
}
|
||||
|
||||
void SqliteDatabase::transaction(const std::function<void(Connection&)>& func) {
|
||||
auto conn = lock();
|
||||
try {
|
||||
SqliteStatement(conn, "BEGIN TRANSACTION").step();
|
||||
func(conn);
|
||||
SqliteStatement(conn, "COMMIT").step();
|
||||
} catch (const std::exception& ex) {
|
||||
SqliteStatement(conn, "ROLLBACK").step();
|
||||
XLOG(WARN) << "SQLite transaction failed: " << ex.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
} // namespace facebook::eden
|
80
eden/fs/sqlite/SqliteDatabase.h
Normal file
80
eden/fs/sqlite/SqliteDatabase.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This software may be used and distributed according to the terms of the
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/Synchronized.h>
|
||||
#include <sqlite3.h>
|
||||
#include "eden/fs/utils/PathFuncs.h"
|
||||
|
||||
namespace facebook::eden {
|
||||
// Given a sqlite result code, if the result was not successful
|
||||
// (SQLITE_OK), format an error message and throw an exception.
|
||||
void checkSqliteResult(sqlite3* db, int result);
|
||||
|
||||
/** A helper class for managing a handle to a sqlite database. */
|
||||
class SqliteDatabase {
|
||||
public:
|
||||
using Connection = folly::Synchronized<sqlite3*>::LockedPtr;
|
||||
|
||||
constexpr static struct InMemory {
|
||||
} inMemory{};
|
||||
|
||||
/** Open a handle to the database at the specified path.
|
||||
* Will throw an exception if the database fails to open.
|
||||
* The database will be created if it didn't already exist.
|
||||
*/
|
||||
explicit SqliteDatabase(AbsolutePathPiece path)
|
||||
: SqliteDatabase(path.copy().c_str()) {}
|
||||
|
||||
/**
|
||||
* Create a SQLite database in memory. It will throw an exception if the
|
||||
* database fails to open. This should be only used in testing.
|
||||
*/
|
||||
explicit SqliteDatabase(InMemory) : SqliteDatabase(":memory:") {}
|
||||
|
||||
// Not copyable...
|
||||
SqliteDatabase(const SqliteDatabase&) = delete;
|
||||
SqliteDatabase& operator=(const SqliteDatabase&) = delete;
|
||||
|
||||
// But movable.
|
||||
SqliteDatabase(SqliteDatabase&&) = default;
|
||||
SqliteDatabase& operator=(SqliteDatabase&&) = default;
|
||||
|
||||
/** Close the handle.
|
||||
* This will happen implicitly at destruction but is provided
|
||||
* here for convenience. */
|
||||
void close();
|
||||
|
||||
~SqliteDatabase();
|
||||
|
||||
/** Obtain a locked database pointer suitable for passing
|
||||
* to the SqliteStatement class. */
|
||||
Connection lock();
|
||||
|
||||
/**
|
||||
* Executes a SQLite transaction. If the lambda body throws any error, the
|
||||
* transaction will be rolled back. This function returns a boolean to
|
||||
* indicate whether the transaction is successfully committed.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* ```
|
||||
* db_->transaction([](auto& conn) {
|
||||
* SqliteStatement(conn, "SELECT * ...").step();
|
||||
* SqliteStatement(conn, "INSERT INTO ...").step();
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
void transaction(const std::function<void(Connection&)>& func);
|
||||
|
||||
private:
|
||||
explicit SqliteDatabase(const char* address);
|
||||
|
||||
folly::Synchronized<sqlite3*> db_{nullptr};
|
||||
};
|
||||
} // namespace facebook::eden
|
@ -5,81 +5,11 @@
|
||||
* GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include "eden/fs/sqlite/Sqlite.h"
|
||||
#include "eden/fs/sqlite/SqliteStatement.h"
|
||||
|
||||
#include <folly/logging/xlog.h>
|
||||
|
||||
using folly::StringPiece;
|
||||
using folly::Synchronized;
|
||||
using folly::to;
|
||||
using std::string;
|
||||
|
||||
namespace facebook {
|
||||
namespace eden {
|
||||
|
||||
// Given a sqlite result code, if the result was not successful
|
||||
// (SQLITE_OK), format an error message and throw an exception.
|
||||
void checkSqliteResult(sqlite3* db, int result) {
|
||||
if (result == SQLITE_OK) {
|
||||
return;
|
||||
}
|
||||
// Sometimes the db instance holds more useful context
|
||||
if (db) {
|
||||
auto error = fmt::format(
|
||||
"sqlite error ({}): {} {}",
|
||||
result,
|
||||
sqlite3_errstr(result),
|
||||
sqlite3_errmsg(db));
|
||||
XLOG(DBG6) << error;
|
||||
throw std::runtime_error(error);
|
||||
} else {
|
||||
auto error =
|
||||
fmt::format("sqlite error ({}): {}", result, sqlite3_errstr(result));
|
||||
XLOG(DBG6) << error;
|
||||
// otherwise resort to a simpler number->string mapping
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
SqliteDatabase::SqliteDatabase(const char* addr) {
|
||||
sqlite3* db = nullptr;
|
||||
auto result = sqlite3_open(addr, &db);
|
||||
if (result != SQLITE_OK) {
|
||||
sqlite3_close(db);
|
||||
checkSqliteResult(nullptr, result);
|
||||
}
|
||||
db_ = db;
|
||||
}
|
||||
|
||||
void SqliteDatabase::close() {
|
||||
auto db = db_.wlock();
|
||||
if (*db) {
|
||||
sqlite3_close(*db);
|
||||
*db = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
SqliteDatabase::~SqliteDatabase() {
|
||||
close();
|
||||
}
|
||||
|
||||
Synchronized<sqlite3*>::LockedPtr SqliteDatabase::lock() {
|
||||
return db_.wlock();
|
||||
}
|
||||
|
||||
void SqliteDatabase::transaction(const std::function<void(Connection&)>& func) {
|
||||
auto conn = lock();
|
||||
try {
|
||||
SqliteStatement(conn, "BEGIN TRANSACTION").step();
|
||||
func(conn);
|
||||
SqliteStatement(conn, "COMMIT").step();
|
||||
} catch (const std::exception& ex) {
|
||||
SqliteStatement(conn, "ROLLBACK").step();
|
||||
XLOG(WARN) << "SQLite transaction failed: " << ex.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#include "eden/fs/sqlite/SqliteDatabase.h"
|
||||
|
||||
namespace facebook::eden {
|
||||
SqliteStatement::SqliteStatement(
|
||||
folly::Synchronized<sqlite3*>::LockedPtr& db,
|
||||
folly::StringPiece query)
|
||||
@ -148,19 +78,18 @@ void SqliteStatement::reset() {
|
||||
checkSqliteResult(db_, sqlite3_clear_bindings(stmt_));
|
||||
}
|
||||
|
||||
StringPiece SqliteStatement::columnBlob(size_t colNo) const {
|
||||
folly::StringPiece SqliteStatement::columnBlob(size_t colNo) const {
|
||||
auto col = unsignedNoToInt(colNo);
|
||||
return StringPiece(
|
||||
return folly::StringPiece(
|
||||
reinterpret_cast<const char*>(sqlite3_column_blob(stmt_, col)),
|
||||
sqlite3_column_bytes(stmt_, col));
|
||||
}
|
||||
|
||||
uint64_t SqliteStatement::columnUint64(size_t colNo) const {
|
||||
return sqlite3_column_int64(stmt_, folly::to_signed(colNo));
|
||||
return sqlite3_column_int64(stmt_, unsignedNoToInt(colNo));
|
||||
}
|
||||
|
||||
SqliteStatement::~SqliteStatement() {
|
||||
sqlite3_finalize(stmt_);
|
||||
}
|
||||
} // namespace eden
|
||||
} // namespace facebook
|
||||
}; // namespace facebook::eden
|
@ -6,80 +6,12 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/String.h>
|
||||
#include <folly/Synchronized.h>
|
||||
#include <sqlite3.h>
|
||||
#include "eden/fs/utils/PathFuncs.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace eden {
|
||||
|
||||
// Given a sqlite result code, if the result was not successful
|
||||
// (SQLITE_OK), format an error message and throw an exception.
|
||||
void checkSqliteResult(sqlite3* db, int result);
|
||||
|
||||
/** A helper class for managing a handle to a sqlite database. */
|
||||
class SqliteDatabase {
|
||||
public:
|
||||
using Connection = folly::Synchronized<sqlite3*>::LockedPtr;
|
||||
|
||||
constexpr static struct InMemory {
|
||||
} inMemory{};
|
||||
|
||||
/** Open a handle to the database at the specified path.
|
||||
* Will throw an exception if the database fails to open.
|
||||
* The database will be created if it didn't already exist.
|
||||
*/
|
||||
explicit SqliteDatabase(AbsolutePathPiece path)
|
||||
: SqliteDatabase(path.copy().c_str()) {}
|
||||
|
||||
/**
|
||||
* Create a SQLite database in memory. It will throw an exception if the
|
||||
* database fails to open. This should be only used in testing.
|
||||
*/
|
||||
explicit SqliteDatabase(InMemory) : SqliteDatabase(":memory:") {}
|
||||
|
||||
// Not copyable...
|
||||
SqliteDatabase(const SqliteDatabase&) = delete;
|
||||
SqliteDatabase& operator=(const SqliteDatabase&) = delete;
|
||||
|
||||
// But movable.
|
||||
SqliteDatabase(SqliteDatabase&&) = default;
|
||||
SqliteDatabase& operator=(SqliteDatabase&&) = default;
|
||||
|
||||
/** Close the handle.
|
||||
* This will happen implicitly at destruction but is provided
|
||||
* here for convenience. */
|
||||
void close();
|
||||
|
||||
~SqliteDatabase();
|
||||
|
||||
/** Obtain a locked database pointer suitable for passing
|
||||
* to the SqliteStatement class. */
|
||||
Connection lock();
|
||||
|
||||
/**
|
||||
* Executes a SQLite transaction. If the lambda body throws any error, the
|
||||
* transaction will be rolled back. This function re-throws any exception
|
||||
* thrown by the closure.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* ```
|
||||
* db_->transaction([](auto& conn) {
|
||||
* SqliteStatement(conn, "SELECT * ...").step();
|
||||
* SqliteStatement(conn, "INSERT INTO ...").step();
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
void transaction(const std::function<void(Connection&)>& func);
|
||||
|
||||
private:
|
||||
explicit SqliteDatabase(const char* address);
|
||||
|
||||
folly::Synchronized<sqlite3*> db_{nullptr};
|
||||
};
|
||||
|
||||
namespace facebook::eden {
|
||||
/** Represents the sqlite vm that will execute a SQL statement.
|
||||
* The class can only be created while holding a lock on the SqliteDatabase;
|
||||
* this is enforced by the compiler. However, the statement class
|
||||
@ -91,7 +23,9 @@ class SqliteDatabase {
|
||||
class SqliteStatement {
|
||||
public:
|
||||
/** Prepare to execute the statement described by the `query` parameter */
|
||||
SqliteStatement(SqliteDatabase::Connection& db, folly::StringPiece query);
|
||||
SqliteStatement(
|
||||
folly::Synchronized<sqlite3*>::LockedPtr& db,
|
||||
folly::StringPiece query);
|
||||
|
||||
/** Join together the arguments as a single query string and prepare a
|
||||
* statement to execute them.
|
||||
@ -101,7 +35,7 @@ class SqliteStatement {
|
||||
* in the cases where the query string is known at compile time. */
|
||||
template <typename Arg1, typename Arg2, typename... Args>
|
||||
SqliteStatement(
|
||||
SqliteDatabase::Connection& db,
|
||||
folly::Synchronized<sqlite3*>::LockedPtr& db,
|
||||
Arg1&& first,
|
||||
Arg2&& second,
|
||||
Args&&... args)
|
||||
@ -179,5 +113,4 @@ class SqliteStatement {
|
||||
/** The statement handle */
|
||||
sqlite3_stmt* stmt_;
|
||||
};
|
||||
} // namespace eden
|
||||
} // namespace facebook
|
||||
} // namespace facebook::eden
|
@ -11,7 +11,7 @@
|
||||
#include <folly/container/Array.h>
|
||||
#include <folly/logging/xlog.h>
|
||||
|
||||
#include "eden/fs/sqlite/Sqlite.h"
|
||||
#include "eden/fs/sqlite/SqliteStatement.h"
|
||||
#include "eden/fs/store/StoreResult.h"
|
||||
|
||||
namespace facebook {
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include <folly/Synchronized.h>
|
||||
#include "eden/fs/sqlite/Sqlite.h"
|
||||
#include "eden/fs/sqlite/SqliteDatabase.h"
|
||||
#include "eden/fs/store/LocalStore.h"
|
||||
|
||||
namespace facebook {
|
||||
|
Loading…
Reference in New Issue
Block a user