Restoring Archive Objects in Batches
This example restores Archive objects in batches. You can specify the list of object keys to be restored, restoration speed (Expedited or Standard), and retention period, and initiate restoration requests concurrently. This method is suitable for batch restoration of a large amount of archived data.
#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";
// Hard-coded or plaintext AK and SK are risky. For security purposes, encrypt your AK and SK before storing them in the configuration file or environment variables. In this example, the AK and SK are stored in environment variables. Before running the code in this example, configure environment variables AccessKeyID and SecretAccessKey.
// Obtain an AK/SK pair on the management console. For details, see https://support.huaweicloud.com/intl/en-us/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;
} What is your overall rating for this page?
Thank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot