更新时间:2026-09-08 GMT+08:00
批量恢复归档或深度归档存储对象(C SDK)
开发过程中,您有任何问题可以在GitHub上提交issue,或者在华为云对象存储服务论坛中发帖求助。
代码示例
本示例用于批量恢复归档或深度归档存储的对象。归档或深度归档类型的对象处于冷冻状态无法直接访问,需要先提交恢复请求,等待恢复完成后才能访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #include "eSDKOBS.h" #define MAX_KEY_LEN 1024 #define MAX_TASK 10000 #define RESTORE_WAIT_SECONDS 6 // 单个对象恢复任务 typedef struct { char key[MAX_KEY_LEN]; obs_status status; } restore_task; // 批量恢复结果统计 typedef struct { int total; int success; int failed; char failed_keys[100][MAX_KEY_LEN]; int failed_count; pthread_mutex_t mutex; } batch_result; static batch_result g_result = {0, 0, 0, {{0}}, 0, PTHREAD_MUTEX_INITIALIZER}; static restore_task *g_tasks = NULL; static int g_task_count = 0; static int g_task_index = 0; static pthread_mutex_t g_task_mutex = PTHREAD_MUTEX_INITIALIZER; // 响应回调函数 static obs_status restore_properties_callback(const obs_response_properties *properties, void *callback_data) { (void)properties; (void)callback_data; return OBS_STATUS_OK; } // 结束回调函数 static void restore_complete_callback(obs_status status, const obs_error_details *error, void *callback_data) { (void)error; restore_task *task = (restore_task *)callback_data; char *key = task ? task->key : "unknown"; if (task) { task->status = status; } pthread_mutex_lock(&g_result.mutex); if (status == OBS_STATUS_OK) { g_result.success++; printf("[SUCCESS] restore %s\n", key); } else { g_result.failed++; if (g_result.failed_count < 100) { strncpy(g_result.failed_keys[g_result.failed_count], key, MAX_KEY_LEN - 1); g_result.failed_keys[g_result.failed_count][MAX_KEY_LEN - 1] = '\0'; g_result.failed_count++; } printf("[FAILED] restore %s: %s\n", key, obs_get_status_name(status)); } pthread_mutex_unlock(&g_result.mutex); } // 列举对象的回调数据 typedef struct { restore_task *tasks; int max_count; int current_count; obs_status ret_status; } list_cb_data; // 列举对象的数据回调 static obs_status list_objects_callback(int is_truncated, const char *next_marker, int contents_count, const obs_list_objects_content *contents, int common_prefixes_count, const char **common_prefixes, void *callback_data) { (void)is_truncated; (void)next_marker; (void)common_prefixes_count; (void)common_prefixes; list_cb_data *data = (list_cb_data *)callback_data; for (int i = 0; i < contents_count && data->current_count < data->max_count; i++) { memset(&data->tasks[data->current_count], 0, sizeof(restore_task)); strncpy(data->tasks[data->current_count].key, contents[i].key, MAX_KEY_LEN - 1); data->tasks[data->current_count].key[MAX_KEY_LEN - 1] = '\0'; data->current_count++; } return OBS_STATUS_OK; } // 列举对象完成回调 static void list_complete_callback(obs_status status, const obs_error_details *error, void *callback_data) { (void)error; list_cb_data *data = (list_cb_data *)callback_data; data->ret_status = status; } // 恢复状态轮询的数据结构 typedef struct { char restore_info[128]; obs_status status; } restore_status_data; static obs_status restore_check_properties_callback(const obs_response_properties *properties, void *callback_data) { restore_status_data *data = (restore_status_data *)callback_data; if (data && properties && properties->restore) { strncpy(data->restore_info, properties->restore, sizeof(data->restore_info) - 1); data->restore_info[sizeof(data->restore_info) - 1] = '\0'; } return OBS_STATUS_OK; } static void restore_check_complete_callback(obs_status status, const obs_error_details *error, void *callback_data) { (void)error; restore_status_data *data = (restore_status_data *)callback_data; if (data) { data->status = status; } } // 等待单个对象恢复完成(轮询对象元数据中的 restore 头) static void wait_until_restore_complete(const obs_options *options, obs_object_info *object_info) { // 恢复完成标记:restore 头以 ongoing-request="false" 开头 const char *prefix = "ongoing-request=\"false\""; obs_response_handler handler = { restore_check_properties_callback, restore_check_complete_callback }; for (;;) { restore_status_data data; memset(&data, 0, sizeof(data)); data.status = OBS_STATUS_BUTT; get_object_metadata(options, object_info, NULL, &handler, &data); if (data.status != OBS_STATUS_OK) { printf("[WARN] get metadata for restore check failed(%s)\n", obs_get_status_name(data.status)); break; } if (data.restore_info[0] != '\0') { // 恢复完成则退出 if (strstr(data.restore_info, prefix) != NULL) { printf("[INFO] %s restore completed: %s\n", object_info->key, data.restore_info); break; } } // 未完成,等待后继续轮询 sleep(RESTORE_WAIT_SECONDS); } } // 工作线程:领取任务 -> 恢复对象 -> 等待恢复完成 static void *worker_thread(void *arg) { obs_options *options_ptr = (obs_options *)arg; const char *stored_days = "1"; obs_tier tier = OBS_TIER_EXPEDITED; while (1) { pthread_mutex_lock(&g_task_mutex); if (g_task_index >= g_task_count) { pthread_mutex_unlock(&g_task_mutex); break; } int idx = g_task_index++; pthread_mutex_unlock(&g_task_mutex); restore_task *task = &g_tasks[idx]; // 构造对象信息 obs_object_info object_info; memset(&object_info, 0, sizeof(obs_object_info)); object_info.key = task->key; object_info.version_id = NULL; // 设置响应回调 obs_response_handler handler = { restore_properties_callback, restore_complete_callback }; // 提交恢复请求 task->status = OBS_STATUS_BUTT; restore_object(options_ptr, &object_info, stored_days, tier, &handler, task); if (task->status != OBS_STATUS_OK) { // restore_complete_callback 已统计失败,跳过等待 continue; } // 等待对象恢复完成 wait_until_restore_complete(options_ptr, &object_info); } return NULL; } int main() { // 本示例用于批量恢复归档或深度归档存储的对象。归档或深度归档类型的对象处于冷冻状态无法直接访问, // 需要先提交恢复请求,等待恢复完成后才能访问。 // 在程序入口调用obs_initialize方法来初始化网络、内存等全局资源。 const char *BUCKET_NAME = "example-bucket-name"; const char *PREFIX = "test/source/"; int THREAD_NUM = 8; obs_status status = obs_initialize(OBS_INIT_ALL); if (status != OBS_STATUS_OK) { printf("obs_initialize failed: %s\n", obs_get_status_name(status)); return 1; } obs_options options; init_obs_options(&options); // host_name填写桶所在的endpoint, 此处以华北-北京四为例,其他地区请按实际情况填写。 options.bucket_options.host_name = "obs.cn-north-4.myhuaweicloud.com"; // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全; // 本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量ACCESS_KEY_ID和SECRET_ACCESS_KEY。 options.bucket_options.access_key = getenv("ACCESS_KEY_ID"); options.bucket_options.secret_access_key = getenv("SECRET_ACCESS_KEY"); options.bucket_options.bucket_name = (char *)BUCKET_NAME; options.request_options.auth_switch = OBS_OBS_TYPE; printf("\nListing objects with prefix '%s'...\n", PREFIX); // 列举指定前缀的对象,收集待恢复对象列表 g_tasks = (restore_task *)malloc(sizeof(restore_task) * MAX_TASK); if (!g_tasks) { printf("Failed to allocate memory\n"); obs_deinitialize(); return 1; } list_cb_data cb_data = {g_tasks, MAX_TASK, 0, OBS_STATUS_BUTT}; obs_list_objects_handler list_handler = { {NULL, list_complete_callback}, list_objects_callback }; list_bucket_objects(&options, PREFIX, NULL, NULL, 1000, &list_handler, &cb_data); if (cb_data.ret_status != OBS_STATUS_OK) { printf("list_bucket_objects failed: %s\n", obs_get_status_name(cb_data.ret_status)); free(g_tasks); obs_deinitialize(); return 1; } g_task_count = cb_data.current_count; if (g_task_count == 0) { printf("No objects found with prefix '%s'\n", PREFIX); free(g_tasks); obs_deinitialize(); return 0; } printf("Found %d objects to restore\n", g_task_count); g_result.total = g_task_count; g_result.success = 0; g_result.failed = 0; g_result.failed_count = 0; g_task_index = 0; // 多线程批量提交恢复请求并等待恢复完成 pthread_t threads[THREAD_NUM]; for (int i = 0; i < THREAD_NUM; i++) { pthread_create(&threads[i], NULL, worker_thread, &options); } for (int i = 0; i < THREAD_NUM; i++) { pthread_join(threads[i], NULL); } // 输出批量恢复统计 printf("\n========== Batch Restore Summary ==========\n"); printf("Total: %d\n", g_result.total); printf("Success: %d\n", g_result.success); printf("Failed: %d\n", g_result.failed); if (g_result.failed_count > 0) { printf("\nFailed objects:\n"); for (int i = 0; i < g_result.failed_count; i++) { printf(" - %s\n", g_result.failed_keys[i]); } } printf("============================================\n"); free(g_tasks); obs_deinitialize(); return 0; } |
相关链接
- 关于恢复归档存储对象的API说明,请参见恢复归档或深度归档存储对象。
- 更多关于恢复归档存储对象的代码示例,请参见Github示例。
- 恢复归档对象过程中返回的错误码含义、问题原因及处理措施可参考OBS错误码。
父主题: 下载对象(C SDK)