Skip to content
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
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions src/cluster_mgr/src/cli/task/backup_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use anyhow::{Context, Result};
use regex::Regex;
use tracing::{info, warn};

pub const ROCKSDB_CLOUD_RESTORE_BRANCH: &str = "main";

/// Join manifest filenames into comma-separated string
/// Validates that manifest filenames don't contain commas
/// For single manifest, returns as-is (backward compatible)
Expand Down Expand Up @@ -329,16 +331,16 @@ pub fn parse_snapshot_manifest(manifest: &str) -> Result<(String, u32, String)>
}

/// Parse current database manifest filename to extract ng_id and epoch
/// Format: CLOUDMANIFEST-development-<ng_id>-<epoch>
/// Format: CLOUDMANIFEST-main-<ng_id>-<epoch>
/// Returns: (ng_id, epoch)
pub fn parse_database_manifest(manifest: &str) -> Result<(u32, u64)> {
// Remove CLOUDMANIFEST- prefix
let manifest = manifest
.strip_prefix("CLOUDMANIFEST-")
.ok_or_else(|| anyhow::anyhow!("Manifest must start with CLOUDMANIFEST-: {}", manifest))?;

// Pattern: development-<ng_id>-<epoch>
let re = Regex::new(r"^development-(\d+)-(\d+)$").context("Failed to compile regex")?;
// Pattern: main-<ng_id>-<epoch>
let re = Regex::new(r"^main-(\d+)-(\d+)$").context("Failed to compile regex")?;

let caps = re
.captures(manifest)
Expand All @@ -353,7 +355,7 @@ pub fn parse_database_manifest(manifest: &str) -> Result<(u32, u64)> {
/// Find maximum epoch for a given ng_id from list of manifest keys
/// Returns the maximum epoch found, or 0 if none found
pub fn find_max_epoch_for_ng(manifest_keys: &[String], ng_id: u32) -> Result<u64> {
let prefix = format!("CLOUDMANIFEST-development-{}-", ng_id);
let prefix = format!("CLOUDMANIFEST-{}-{}-", ROCKSDB_CLOUD_RESTORE_BRANCH, ng_id);
let mut max_epoch = 0u64;

for key in manifest_keys {
Expand Down
21 changes: 16 additions & 5 deletions src/cluster_mgr/src/cli/task/s3_restore_task.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::cli::task::backup_utils::{
find_max_epoch_for_ng, parse_database_manifest, parse_snapshot_manifest, split_manifests,
ROCKSDB_CLOUD_RESTORE_BRANCH,
};
use crate::cli::task::s3_utils::{copy_s3_object, list_s3_objects, S3ClientBuilder};
use crate::cli::task::task_base::{ExecutionValue, TaskArgValue, TaskExecutor, TaskHost, TaskId};
Expand All @@ -10,6 +11,10 @@ use async_trait::async_trait;
use std::collections::{HashMap, HashSet};
use tracing::{error, info, warn};

// TODO: Read the object path and branch name from cluster configuration, and derive
// the ds_<shard_id> path for every snapshot manifest in multi-shard deployments.
const ROCKSDB_CLOUD_RESTORE_OBJECT_PATH: &str = "rocksdb_cloud/ds_0";

#[derive(Clone, Debug)]
pub struct S3RestoreTask {
task_id: TaskId,
Expand Down Expand Up @@ -100,8 +105,11 @@ impl TaskExecutor for S3RestoreTask {
info!("Found {} manifest(s) to restore", manifest_list.len());

// List all current database manifests to find max epochs
let db_manifest_prefix = "rocksdb_cloud/CLOUDMANIFEST-development-";
let all_manifests = list_s3_objects(&s3_client, &self.bucket, db_manifest_prefix)
let db_manifest_prefix = format!(
"{}/CLOUDMANIFEST-{}-",
ROCKSDB_CLOUD_RESTORE_OBJECT_PATH, ROCKSDB_CLOUD_RESTORE_BRANCH
);
let all_manifests = list_s3_objects(&s3_client, &self.bucket, &db_manifest_prefix)
.await
.context("Failed to list current database manifests")?;

Expand Down Expand Up @@ -133,7 +141,10 @@ impl TaskExecutor for S3RestoreTask {
);

// Construct source S3 key
let source_key = format!("rocksdb_cloud/CLOUDMANIFEST-{}", snapshot_manifest);
let source_key = format!(
"{}/CLOUDMANIFEST-{}",
ROCKSDB_CLOUD_RESTORE_OBJECT_PATH, snapshot_manifest
);

// Check if source file exists
match s3_client
Expand Down Expand Up @@ -172,8 +183,8 @@ impl TaskExecutor for S3RestoreTask {

// Construct destination S3 key
let dest_key = format!(
"rocksdb_cloud/CLOUDMANIFEST-development-{}-{}",
ng_id, new_epoch
"{}/CLOUDMANIFEST-{}-{}-{}",
ROCKSDB_CLOUD_RESTORE_OBJECT_PATH, ROCKSDB_CLOUD_RESTORE_BRANCH, ng_id, new_epoch
);

// Copy manifest file
Expand Down
2 changes: 1 addition & 1 deletion src/cluster_mgr/src/config/storage_service_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ impl StorageService {
s3.aws_access_key_id.clone(),
s3.aws_secret_key.clone(),
s3.region.clone(),
None,
s3.endpoint.clone(),
))
}
RocksDB::MINIO(minio) => {
Expand Down
Loading