Skip to content

Commit f145663

Browse files
author
yawzhang
committed
Add API to trigger snapshot creation manually
1 parent 2e63ecf commit f145663

File tree

6 files changed

+80
-4
lines changed

6 files changed

+80
-4
lines changed

conanfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
class HomeObjectConan(ConanFile):
1212
name = "homeobject"
13-
version = "4.0.8"
13+
version = "4.0.9"
1414

1515
homepage = "https://github.com/eBay/HomeObject"
1616
description = "Blob Store built on HomeStore"

src/lib/homestore_backend/hs_homeobject.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,4 +550,15 @@ void HSHomeObject::yield_pg_leadership_to_follower(int32_t pg_id) {
550550
}
551551
}
552552

553+
void HSHomeObject::trigger_snapshot_creation(int32_t pg_id, int64_t compact_lsn, bool is_async, bool wait_for_commit) {
554+
LOGI("Triggering snapshot creation for pg_id={}, compact_lsn={}, is_async={}, wait_for_commit={}", pg_id,
555+
compact_lsn, is_async, wait_for_commit);
556+
auto hs_pg = get_hs_pg(pg_id);
557+
if (!hs_pg) {
558+
LOGE("Failed to trigger snapshot: PG {} not found", pg_id);
559+
return;
560+
}
561+
hs_pg->trigger_snapshot_creation(compact_lsn, is_async, wait_for_commit);
562+
}
563+
553564
} // namespace homeobject

src/lib/homestore_backend/hs_homeobject.hpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ class HSHomeObject : public HomeObjectImpl {
5454
uint32_t _hs_reserved_blks = 0;
5555

5656
/// Overridable Helpers
57-
ShardManager::AsyncResult< ShardInfo > _create_shard(pg_id_t, uint64_t size_bytes, std::string meta, trace_id_t tid) override;
57+
ShardManager::AsyncResult< ShardInfo > _create_shard(pg_id_t, uint64_t size_bytes, std::string meta,
58+
trace_id_t tid) override;
5859
ShardManager::AsyncResult< ShardInfo > _seal_shard(ShardInfo const&, trace_id_t tid) override;
5960

6061
BlobManager::AsyncResult< blob_id_t > _put_blob(ShardInfo const&, Blob&&, trace_id_t tid) override;
@@ -196,7 +197,7 @@ class HSHomeObject : public HomeObjectImpl {
196197
};
197198

198199
struct shard_info_superblk : DataHeader {
199-
//This version is a common version of DataHeader, each derived struct can have its own version.
200+
// This version is a common version of DataHeader, each derived struct can have its own version.
200201
static constexpr uint8_t shard_sb_version = 0x02;
201202

202203
uint8_t sb_version{shard_sb_version};
@@ -394,6 +395,8 @@ class HSHomeObject : public HomeObjectImpl {
394395

395396
void yield_leadership_to_follower() const;
396397

398+
void trigger_snapshot_creation(int64_t compact_lsn, bool is_async, bool wait_for_commit) const;
399+
397400
/**
398401
* Returns all shards
399402
*/
@@ -437,7 +440,7 @@ class HSHomeObject : public HomeObjectImpl {
437440
uint32_t data_offset; // Offset of actual data blob stored after the metadata
438441
uint32_t user_key_size; // Actual size of the user key.
439442
uint8_t user_key[max_user_key_length + 1]{};
440-
uint8_t padding[2956]{}; // data_block_size is 4K, so total size of BlobHeader is 4096 bytes
443+
uint8_t padding[2956]{}; // data_block_size is 4K, so total size of BlobHeader is 4096 bytes
441444

442445
std::optional< std::string > get_user_key() const {
443446
if (user_key_size > max_user_key_length) { return std::nullopt; }
@@ -969,6 +972,22 @@ class HSHomeObject : public HomeObjectImpl {
969972
*/
970973
void yield_pg_leadership_to_follower(int32_t pg_id = 1);
971974

975+
/**
976+
* @brief Manually trigger a snapshot creation.
977+
* @param compact_lsn Expected compact up to LSN. Default is -1, meaning it depends directly on the current HS
978+
* status.
979+
* @param is_async Trigger mode. Default is true, meaning an async snapshot is triggered on the next earliest
980+
* committed log. If false, a snapshot is triggered immediately based on the latest committed log.
981+
* @param wait_for_commit Wait committed lsn reaches compact_lsn. Default is true, false means the snapshot will be
982+
* triggered based on its latest committed lsn and the log compaction depends on min(snapshot_lsn, compact_lsn)
983+
*
984+
* Recommendation:
985+
* - If there is continuous traffic, it is recommended to set is_async=true. This only sets a flag, relying on
986+
* subsequent commits to trigger the snapshot asynchronously, making it more lightweight.
987+
* - If there is no continuous traffic, set is_async=false to trigger a snapshot immediately.
988+
*/
989+
void trigger_snapshot_creation(int32_t pg_id, int64_t compact_lsn, bool is_async, bool wait_for_commit);
990+
972991
// Blob manager related.
973992
void on_blob_message_rollback(int64_t lsn, sisl::blob const& header, sisl::blob const& key,
974993
cintrusive< homestore::repl_req_ctx >& hs_ctx);

src/lib/homestore_backend/hs_http_manager.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ HttpManager::HttpManager(HSHomeObject& ho) : ho_(ho) {
3737
Pistache::Rest::Routes::bind(&HttpManager::reconcile_leader, this)},
3838
{Pistache::Http::Method::Post, "/api/v1/yield_leadership_to_follower",
3939
Pistache::Rest::Routes::bind(&HttpManager::yield_leadership_to_follower, this)},
40+
{Pistache::Http::Method::Post, "/api/v1/trigger_snapshot_creation",
41+
Pistache::Rest::Routes::bind(&HttpManager::trigger_snapshot_creation, this)},
4042
#ifdef _PRERELEASE
4143
{Pistache::Http::Method::Post, "/api/v1/crashSystem",
4244
Pistache::Rest::Routes::bind(&HttpManager::crash_system, this)},
@@ -91,6 +93,45 @@ void HttpManager::yield_leadership_to_follower(const Pistache::Rest::Request& re
9193
response.send(Pistache::Http::Code::Ok, "Yield leadership request submitted");
9294
}
9395

96+
void HttpManager::trigger_snapshot_creation(const Pistache::Rest::Request& request,
97+
Pistache::Http::ResponseWriter response) {
98+
// Extract and validate pg_id parameter (required)
99+
const auto pg_id_param = request.query().get("pg_id");
100+
if (!pg_id_param) {
101+
response.send(Pistache::Http::Code::Bad_Request, "pg_id is required");
102+
return;
103+
}
104+
const int32_t pg_id = std::stoi(pg_id_param.value());
105+
106+
// Extract compact_lsn parameter (optional, default: -1 means use current HS status)
107+
const auto compact_lsn_param = request.query().get("compact_lsn");
108+
const int64_t compact_lsn = std::stoll(compact_lsn_param.value_or("-1"));
109+
110+
// Extract and validate is_async parameter (optional, default: false)
111+
const auto is_async_param = request.query().get("is_async");
112+
std::string is_async_mode = is_async_param.value_or("false");
113+
if (is_async_mode != "true" && is_async_mode != "false") {
114+
response.send(Pistache::Http::Code::Bad_Request, "is_async must be 'true' or 'false'");
115+
return;
116+
}
117+
bool is_async = (is_async_mode == "true");
118+
119+
// Extract wait_for_commit parameter (optional, default: true)
120+
const auto wait_for_commit_param = request.query().get("wait_for_commit");
121+
std::string wait_for_commit_mode = wait_for_commit_param.value_or("true");
122+
if (wait_for_commit_mode != "true" && wait_for_commit_mode != "false") {
123+
response.send(Pistache::Http::Code::Bad_Request, "wait_for_commit must be 'true' or 'false'");
124+
return;
125+
}
126+
bool wait_for_commit = (wait_for_commit_mode == "true");
127+
128+
LOGINFO("Received snapshot creation request for pg_id={}, compact_lsn={}, is_async={}, wait_for_commit={}", pg_id,
129+
compact_lsn, is_async, wait_for_commit);
130+
131+
ho_.trigger_snapshot_creation(pg_id, compact_lsn, is_async, wait_for_commit);
132+
response.send(Pistache::Http::Code::Ok, "Snapshot creation request submitted");
133+
}
134+
94135
void HttpManager::get_pg(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response) {
95136
auto pg_str = request.query().get("pg_id");
96137
if (!pg_str) {

src/lib/homestore_backend/hs_http_manager.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class HttpManager {
2828
void get_malloc_stats(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response);
2929
void reconcile_leader(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response);
3030
void yield_leadership_to_follower(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response);
31+
void trigger_snapshot_creation(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response);
3132
void get_pg(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response);
3233
void get_pg_chunks(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response);
3334
void dump_chunk(const Pistache::Rest::Request& request, Pistache::Http::ResponseWriter response);

src/lib/homestore_backend/hs_pg_manager.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,10 @@ void HSHomeObject::HS_PG::yield_leadership_to_follower() const {
797797
repl_dev_->yield_leadership(false /*immediate_yield*/, candidate_leader_id);
798798
}
799799

800+
void HSHomeObject::HS_PG::trigger_snapshot_creation(int64_t compact_lsn, bool is_async, bool wait_for_commit) const {
801+
repl_dev_->trigger_snapshot_creation(compact_lsn, is_async, wait_for_commit);
802+
}
803+
800804
std::vector< Shard > HSHomeObject::HS_PG::get_chunk_shards(chunk_num_t v_chunk_id) const {
801805
std::vector< Shard > ret;
802806
for (auto const& s : shards_) {

0 commit comments

Comments
 (0)