更新时间: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;
}

相关链接

相关文档