更新时间:2026-08-28 GMT+08:00
分享

批量恢复归档存储对象

本示例用于批量恢复归档存储中的对象。您可以指定待恢复的对象Key列表、恢复速率(Expedited/Standard)和保留天数,并发发起恢复请求,适用于大规模归档数据的批量恢复场景。

#import <Foundation/Foundation.h>
#import <OBS/OBS.h>
#pragma mark - Result Model
@interface BatchRestoreResult : NSObject
@property (nonatomic, copy) NSString *objectKey;
@property (nonatomic, assign) BOOL success;
@property (nonatomic, strong) NSError *error;
@property (nonatomic, copy) NSString *httpStatusCode;
@end
@implementation BatchRestoreResult
@end
#pragma mark - Batch Restorer
@interface BatchArchiveRestorer : NSObject
@property (nonatomic, strong) OBSClient *client;
@property (nonatomic, copy) NSString *bucketName;
@property (nonatomic, assign) NSInteger concurrentCount;
@property (nonatomic, assign) OBSRestoreTier restoreTier;
@property (nonatomic, assign) NSInteger storeDays;
@property (nonatomic, strong) NSMutableArray<BatchRestoreResult *> *results;
@property (nonatomic, strong) dispatch_queue_t resultQueue;
- (instancetype)initWithClient:(OBSClient *)client
                    bucketName:(NSString *)bucketName
               concurrentCount:(NSInteger)concurrentCount
                    restoreTier:(OBSRestoreTier)restoreTier
                     storeDays:(NSInteger)storeDays;
- (void)restoreObjects:(NSArray<NSString *> *)objectKeys
          waitUntilDone:(BOOL)wait;
@end
@implementation BatchArchiveRestorer
- (instancetype)initWithClient:(OBSClient *)client
                    bucketName:(NSString *)bucketName
               concurrentCount:(NSInteger)concurrentCount
                    restoreTier:(OBSRestoreTier)restoreTier
                     storeDays:(NSInteger)storeDays {
    self = [super init];
    if (self) {
        _client = client;
        _bucketName = bucketName;
        _concurrentCount = MIN(concurrentCount > 0 ? concurrentCount : 3, 10);
        _restoreTier = restoreTier;
        _storeDays = (storeDays > 0 && storeDays <= 30) ? storeDays : 1;
        _results = [NSMutableArray array];
        _resultQueue = dispatch_queue_create("com.obs.batchrestore.result", DISPATCH_QUEUE_SERIAL);
    }
    return self;
}
- (void)restoreObjects:(NSArray<NSString *> *)objectKeys
          waitUntilDone:(BOOL)wait {
    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(self.concurrentCount);
    dispatch_queue_t queue = dispatch_queue_create("com.obs.batchrestore", DISPATCH_QUEUE_CONCURRENT);
    NSString *tierStr = (self.restoreTier == OBSRestoreTierExpedited) ? @"Expedited" : @"Standard";
    NSLog(@"[BatchRestore] Starting %lu restores, concurrency: %ld, tier: %@, days: %ld",
          (unsigned long)objectKeys.count, (long)self.concurrentCount, tierStr, (long)self.storeDays);
    for (NSString *objectKey in objectKeys) {
        dispatch_group_enter(group);
        dispatch_async(queue, ^{
            dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 300 * NSEC_PER_SEC));
            [self restoreObject:objectKey completion:^{
                dispatch_semaphore_signal(semaphore);
                dispatch_group_leave(group);
            }];
        });
    }
    if (wait) {
        dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 300 * NSEC_PER_SEC));
        [self printSummary];
    }
}
- (void)restoreObject:(NSString *)objectKey completion:(void (^)(void))completion {
    OBSRestoreObjectRequest *request = [[OBSRestoreObjectRequest alloc] initWithBucketName:self.bucketName
                                                                                objectKey:objectKey
                                                                                storeDays:@(self.storeDays)];
    request.restoreTier = self.restoreTier;
    __weak typeof(self) weakSelf = self;    __strong typeof(weakSelf) strongSelf = weakSelf;    if (!strongSelf) return;    [self.client restoreObject:request completionHandler:^(OBSRestoreObjectResponse *response, NSError *error) {
        BatchRestoreResult *result = [[BatchRestoreResult alloc] init];
        result.objectKey = objectKey;
        result.error = error;
        result.success = (error == nil);
        result.httpStatusCode = response.statusCode ?: @"-";
        if (error) {
            NSLog(@"[Restore] FAILED - %@ : %@", objectKey, error.localizedDescription);
        } else {
            NSLog(@"[Restore] SUCCESS - %@ (HTTP %@)", objectKey, result.httpStatusCode);
        }
        dispatch_sync(strongSelf.resultQueue, ^{ [strongSelf.results addObject:result]; });
        if (completion) completion();
    }];
}
- (void)printSummary {
    NSInteger success = 0, failure = 0;
    for (BatchRestoreResult *r in self.results) {
        if (r.success) success++;
        else failure++;
    }
    NSLog(@"\n========== Batch Restore Summary ==========");
    NSLog(@"Total: %lu | Success: %ld | Failed: %ld", (unsigned long)self.results.count, (long)success, (long)failure);
    if (failure > 0) {
        NSLog(@"Failed items:");
        for (BatchRestoreResult *r in self.results) {
            if (!r.success) {
                NSLog(@"  - %@ : %@", r.objectKey, r.error.localizedDescription);
            }
        }
    }
    NSLog(@"============================================\n");
}
@end
#pragma mark - Entry Point
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // === Configuration ===
        NSString *endPoint = @"https://your-endpoint";
        // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;本示例以ak和sk保存在环境变量中为例,运行本示例前请先在本地环境中设置环境变量AccessKeyID和SecretAccessKey。
        // 您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
        char* ak_env = getenv("AccessKeyID");
        char* sk_env = getenv("SecretAccessKey");
        if (ak_env == NULL || sk_env == NULL) {
            NSLog(@"Error: AccessKeyID or SecretAccessKey environment variable not set");
            return 1;
        }
        NSString *AK = [NSString stringWithUTF8String:ak_env];
        NSString *SK = [NSString stringWithUTF8String:sk_env];
        NSString *bucketName = @"your-bucket-name";
        NSInteger concurrentCount = 3;  // Adjust as needed
        // Restore options
        OBSRestoreTier restoreTier = OBSRestoreTierStandard;  // or OBSRestoreTierExpedited
        NSInteger storeDays = 1;                              // 1-30 days
        // Objects to restore (must be in Archive or Cold storage class)
        NSArray<NSString *> *objectKeys = @[
            @"archive_folder/doc1.pdf",
            @"archive_folder/doc2.jpg",
            @"archive_folder/doc3.zip",
            @"archive_folder/doc4.mp4",
            @"archive_folder/doc5.tar"
        ];
        // === Initialize OBS Client ===
        OBSStaticCredentialProvider *credentialProvider = [[OBSStaticCredentialProvider alloc] initWithAccessKey:AK secretKey:SK];
        OBSServiceConfiguration *conf = [[OBSServiceConfiguration alloc] initWithURLString:endPoint credentialProvider:credentialProvider];
        OBSClient *client = [[OBSClient alloc] initWithConfiguration:conf];
        // === Batch Restore ===
        BatchArchiveRestorer *restorer = [[BatchArchiveRestorer alloc] initWithClient:client
                                                                          bucketName:bucketName
                                                                     concurrentCount:concurrentCount
                                                                          restoreTier:restoreTier
                                                                           storeDays:storeDays];
        [restorer restoreObjects:objectKeys waitUntilDone:YES];
    }
    return 0;
}

相关文档