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

Commit

Permalink
rgw/sfs: Convert SQLiteList::versions to sqlite_modern_cpp
Browse files Browse the repository at this point in the history
Convert versions listing to sqlite_modern_cpp and add all necessary
type bindings (ObjectState, VersionType, ceph::real_time)

Signed-off-by: Marcel Lauhoff <marcel.lauhoff@suse.com>
  • Loading branch information
Marcel Lauhoff committed Oct 25, 2023
1 parent 99e0a16 commit 8d384d3
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 74 deletions.
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
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
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

0 comments on commit 8d384d3

Please sign in to comment.