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

First Steps Towards Replacing sqlite_orm with sqlite_modern_cpp #238

Merged
merged 3 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,6 @@
[submodule "src/rgw/driver/sfs/sqlite/sqlite_orm"]
path = src/rgw/driver/sfs/sqlite/sqlite_orm
url = https://github.com/aquarist-labs/sqlite_orm.git
[submodule "src/rgw/driver/sfs/sqlite_modern_cpp"]
path = src/rgw/driver/sfs/sqlite/sqlite_modern_cpp
url = https://github.com/SqliteModernCpp/sqlite_modern_cpp.git
1 change: 1 addition & 0 deletions src/rgw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ endif()

if(WITH_RADOSGW_SFS)
target_include_directories(rgw_common PUBLIC "${CMAKE_SOURCE_DIR}/src/rgw/store/sfs")
target_include_directories(rgw_common PUBLIC "${CMAKE_SOURCE_DIR}/src/rgw/store/sfs/sqlite/sqlite_modern_cpp/hdr")
target_link_libraries(rgw_common PRIVATE global sfs)
endif()

Expand Down
1 change: 1 addition & 0 deletions src/rgw/driver/sfs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ set(sfs_srcs
sqlite/dbconn.cc
sqlite/errors.cc
sqlite/sqlite_list.cc
sqlite/conversion_utils.cc
bucket.cc
multipart.cc
object.cc
Expand Down
33 changes: 33 additions & 0 deletions src/rgw/driver/sfs/object_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
#define RGW_SFS_OBJECT_STATE_H

#include <iostream>

#include "include/ceph_assert.h"
#if FMT_VERSION >= 90000
#include <fmt/ostream.h>
#endif
#include "sqlite/dbapi.h"

namespace rgw::sal::sfs {

Expand Down Expand Up @@ -47,6 +50,36 @@ inline std::string str_object_state(ObjectState state) {
return result;
}

template <>
struct dbapi::sqlite::has_sqlite_type<ObjectState, SQLITE_INTEGER, void>
: ::std::true_type {};

inline int bind_col_in_db(
sqlite3_stmt* stmt, int inx, const rgw::sal::sfs::ObjectState& val
) {
return sqlite3_bind_int(stmt, inx, static_cast<int>(val));
}
inline void store_result_in_db(
sqlite3_context* db, const rgw::sal::sfs::ObjectState& val
) {
sqlite3_result_int(db, static_cast<int>(val));
}
inline rgw::sal::sfs::ObjectState
get_col_from_db(sqlite3_stmt* stmt, int inx, dbapi::sqlite::result_type<rgw::sal::sfs::ObjectState>) {
if (sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
ceph_abort_msg("cannot make enum value from NULL");
}
return static_cast<rgw::sal::sfs::ObjectState>(sqlite3_column_int(stmt, inx));
}

inline rgw::sal::sfs::ObjectState
get_val_from_db(sqlite3_value* value, dbapi::sqlite::result_type<rgw::sal::sfs::ObjectState>) {
if (sqlite3_value_type(value) == SQLITE_NULL) {
ceph_abort_msg("cannot make enum value from NULL");
}
return static_cast<rgw::sal::sfs::ObjectState>(sqlite3_value_int(value));
}

} // namespace rgw::sal::sfs

inline std::ostream& operator<<(
Expand Down
40 changes: 40 additions & 0 deletions src/rgw/driver/sfs/sqlite/bindings/real_time.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#pragma once

#include "common/ceph_time.h"
#include "include/ceph_assert.h"
#include "rgw/driver/sfs/sqlite/dbapi.h"
#include "rgw/driver/sfs/sqlite/sqlite_orm.h"

/// ceph::real_time is represented as a uint64 (unsigned).
Expand Down Expand Up @@ -90,3 +92,41 @@ struct row_extractor<ceph::real_time> {
};

} // namespace sqlite_orm

namespace rgw::sal::sfs::dbapi::sqlite {

template <>
struct has_sqlite_type<ceph::real_time, SQLITE_INTEGER, void>
: ::std::true_type {};

inline int bind_col_in_db(
sqlite3_stmt* stmt, int inx, const ceph::real_time& val
) {
return sqlite3_bind_int64(
stmt, inx, rgw::sal::sfs::sqlite::time_point_to_int64(val)
);
}
inline void store_result_in_db(
sqlite3_context* db, const ceph::real_time& val
) {
sqlite3_result_int64(db, rgw::sal::sfs::sqlite::time_point_to_int64(val));
}
inline ceph::real_time
get_col_from_db(sqlite3_stmt* stmt, int inx, result_type<ceph::real_time>) {
if (sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
ceph_abort_msg("cannot make enum value from NULL");
}
return rgw::sal::sfs::sqlite::time_point_from_int64(
sqlite3_column_int64(stmt, inx)
);
}

inline ceph::real_time
get_val_from_db(sqlite3_value* value, result_type<ceph::real_time>) {
if (sqlite3_value_type(value) == SQLITE_NULL) {
ceph_abort_msg("cannot make enum value from NULL");
}
return rgw::sal::sfs::sqlite::time_point_from_int64(sqlite3_value_int64(value)
);
}
} // namespace rgw::sal::sfs::dbapi::sqlite
37 changes: 37 additions & 0 deletions src/rgw/driver/sfs/sqlite/conversion_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t
// vim: ts=8 sw=2 smarttab ft=cpp
/*
* Ceph - scalable distributed file system
* SFS SAL implementation
*
* Copyright (C) 2023 SUSE LLC
*
* This is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software
* Foundation. See file COPYING.
*/

#include <string>

namespace rgw::sal::sfs::sqlite {

std::string prefix_to_escaped_like(const std::string& prefix, char escape) {
std::string like_expr;
like_expr.reserve(prefix.length() + 10);
for (const char c : prefix) {
switch (c) {
case '%':
[[fallthrough]];
case '_':
like_expr.push_back(escape);
[[fallthrough]];
default:
like_expr.push_back(c);
}
}
like_expr.push_back('%');
return like_expr;
}

} // namespace rgw::sal::sfs::sqlite
16 changes: 3 additions & 13 deletions src/rgw/driver/sfs/sqlite/conversion_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,22 +128,12 @@ void assign_db_value(const SOURCE& source, std::vector<char>& dest) {
dest = blob_vector;
}

std::string prefix_to_escaped_like(const std::string& prefix, char escape);

template <typename COL>
sqlite_orm::internal::like_t<COL, std::basic_string<char>, const char*>
prefix_to_like(COL col, const std::string& prefix) {
std::string like_expr;
like_expr.reserve(prefix.length() + 10);
for (const char c : prefix) {
switch (c) {
case '%':
case '_':
like_expr.push_back('\a');
default:
like_expr.push_back(c);
}
}
like_expr.push_back('%');
return sqlite_orm::like(col, like_expr, "\a");
return sqlite_orm::like(col, prefix_to_escaped_like(prefix, '\a'), "\a");
}

} // namespace rgw::sal::sfs::sqlite
9 changes: 9 additions & 0 deletions src/rgw/driver/sfs/sqlite/dbapi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include <sqlite3.h>

namespace rgw::sal::sfs::dbapi {

#include "sqlite_modern_cpp/hdr/sqlite_modern_cpp.h"

} // namespace rgw::sal::sfs::dbapi
7 changes: 7 additions & 0 deletions src/rgw/driver/sfs/sqlite/dbconn.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "buckets/multipart_definitions.h"
#include "common/ceph_mutex.h"
#include "common/dout.h"
#include "dbapi.h"
#include "lifecycle/lifecycle_definitions.h"
#include "objects/object_definitions.h"
#include "rgw/rgw_perf_counters.h"
Expand Down Expand Up @@ -255,6 +256,8 @@ inline auto _make_storage(const std::string& path) {
using Storage = decltype(_make_storage(""));
using StorageRef = Storage*;

// TODO(https://github.com/aquarist-labs/s3gw/issues/788): Make
// dbapi::sqlite::database the primary interface for sqlite3.
class DBConn {
private:
std::unordered_map<std::thread::id, Storage> storage_pool;
Expand Down Expand Up @@ -282,6 +285,10 @@ class DBConn {
return sqlite_conns;
}

dbapi::sqlite::database get() {
return dbapi::sqlite::database(get_storage()->filename());
}

static std::string getDBPath(CephContext* cct) {
auto rgw_sfs_path = cct->_conf.get_val<std::string>("rgw_sfs_data_path");
auto db_path =
Expand Down
102 changes: 41 additions & 61 deletions src/rgw/driver/sfs/sqlite/sqlite_list.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include <limits>

#include "dbapi.h"
#include "rgw/driver/sfs/sqlite/conversion_utils.h"
#include "rgw/driver/sfs/sqlite/objects/object_definitions.h"
#include "rgw/driver/sfs/sqlite/versioned_object/versioned_object_definitions.h"
Expand Down Expand Up @@ -101,64 +102,45 @@ bool SQLiteList::versions(
// more available logic: request one more than max. if we get that
// much set out_more_available, but return only up to max
ceph_assert(max < std::numeric_limits<size_t>::max());
const size_t query_limit = max + 1;

auto storage = conn->get_storage();
auto rows = storage->select(
columns(
&DBObject::name, &DBVersionedObject::version_id,
&DBVersionedObject::mtime, &DBVersionedObject::etag,
&DBVersionedObject::size, &DBVersionedObject::version_type,
is_equal(
// IsLatest logic
// - Use the id as secondary condition if multiple version
// with same max(commit_time) exists
sqlite_orm::select(
&DBVersionedObject::id, from<DBVersionedObject>(),
where(
is_equal(
&DBObject::uuid, &DBVersionedObject::object_id
) and
is_equal(
&DBVersionedObject::object_state,
ObjectState::COMMITTED
)
),
multi_order_by(
order_by(&DBVersionedObject::commit_time).desc(),
order_by(&DBVersionedObject::id).desc()
),
limit(1)
),
&DBVersionedObject::id
)
),
inner_join<DBVersionedObject>(
on(is_equal(&DBObject::uuid, &DBVersionedObject::object_id))
),
where(
is_equal(&DBVersionedObject::object_state, ObjectState::COMMITTED) and
is_equal(&DBObject::bucket_id, bucket_id) and
greater_than(&DBObject::name, start_after_object_name) and
prefix_to_like(&DBObject::name, prefix)
),
// Sort:
// names a-Z
// first delete markers, then versions - (See: LC CurrentExpiration)
// newest to oldest version
multi_order_by(
order_by(&DBObject::name).asc(),
order_by(&DBVersionedObject::commit_time).desc(),
order_by(&DBVersionedObject::id).desc()
),
limit(query_limit)
);

ceph_assert(rows.size() <= static_cast<size_t>(query_limit));
const size_t return_limit = std::min(max, rows.size());
out.reserve(return_limit);
for (size_t i = 0; i < return_limit; i++) {
const auto& row = rows[i];
const uint32_t query_limit = max + 1;
dbapi::sqlite::database db = conn->get();
auto rows = db << R"sql(
SELECT
o.name, vo.version_id, vo.mtime, vo.etag, vo.size, vo.version_type,
(vo.id = ( SELECT id FROM versioned_objects
WHERE object_id = o.uuid
AND object_state = ?
ORDER BY commit_time desc, id desc
LIMIT 1
)) AS is_latest
FROM objects as o
INNER JOIN versioned_objects as vo
ON (o.uuid = vo.object_id)
WHERE vo.object_state = ?
AND o.bucket_id = ?
AND o.name > ?
AND o.name LIKE ? ESCAPE CHAR(7)
ORDER BY o.name ASC,
vo.commit_time DESC,
vo.id DESC
LIMIT ?;)sql"
<< ObjectState::COMMITTED << ObjectState::COMMITTED
<< bucket_id << start_after_object_name
<< prefix_to_escaped_like(prefix, '\a') << query_limit;
out.reserve(max);
if (out_more_available) {
*out_more_available = false;
}
for (std::tuple<
std::string, std::string, ceph::real_time, std::string, int64_t,
VersionType, bool>
row : rows) {
if (out.size() >= max) {
if (out_more_available) {
*out_more_available = true;
}
break;
}
rgw_bucket_dir_entry e;
e.key.name = std::get<0>(row);
e.key.instance = std::get<1>(row);
Expand All @@ -169,9 +151,7 @@ bool SQLiteList::versions(
e.flags = to_dentry_flag(std::get<5>(row), std::get<6>(row));
out.emplace_back(e);
}
if (out_more_available) {
*out_more_available = rows.size() == query_limit;
}

return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/rgw/driver/sfs/sqlite/sqlite_modern_cpp
Submodule sqlite_modern_cpp added at 232797
32 changes: 32 additions & 0 deletions src/rgw/driver/sfs/version_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#ifndef RGW_SFS_VERSION_TYPE_H
#define RGW_SFS_VERSION_TYPE_H

#include "sqlite/dbapi.h"

namespace rgw::sal::sfs {

enum class VersionType {
Expand All @@ -22,6 +24,36 @@ enum class VersionType {
LAST_VALUE = DELETE_MARKER
};

template <>
struct dbapi::sqlite::has_sqlite_type<VersionType, SQLITE_INTEGER, void>
: ::std::true_type {};

inline int bind_col_in_db(
sqlite3_stmt* stmt, int inx, const rgw::sal::sfs::VersionType& val
) {
return sqlite3_bind_int(stmt, inx, static_cast<int>(val));
}
inline void store_result_in_db(
sqlite3_context* db, const rgw::sal::sfs::VersionType& val
) {
sqlite3_result_int(db, static_cast<int>(val));
}
inline rgw::sal::sfs::VersionType
get_col_from_db(sqlite3_stmt* stmt, int inx, dbapi::sqlite::result_type<rgw::sal::sfs::VersionType>) {
if (sqlite3_column_type(stmt, inx) == SQLITE_NULL) {
ceph_abort_msg("cannot make enum value from NULL");
}
return static_cast<rgw::sal::sfs::VersionType>(sqlite3_column_int(stmt, inx));
}

inline rgw::sal::sfs::VersionType
get_val_from_db(sqlite3_value* value, dbapi::sqlite::result_type<rgw::sal::sfs::VersionType>) {
if (sqlite3_value_type(value) == SQLITE_NULL) {
ceph_abort_msg("cannot make enum value from NULL");
}
return static_cast<rgw::sal::sfs::VersionType>(sqlite3_value_int(value));
}

} // namespace rgw::sal::sfs

#endif // RGW_SFS_VERSION_TYPE_H
Loading
Loading