Skip to content

Commit 6778296

Browse files
Preserve the pending restore request on archive completion
The archive completion write replaced the whole archive block with the archiveInfo returned by the cold backend, dropping a restore request recorded while the object was still awaiting its first archive: the queue populator would then see the completion write with no request to act upon, and the restore would stay pending forever. Issue: BB-804
1 parent 8f51c0c commit 6778296

3 files changed

Lines changed: 50 additions & 3 deletions

File tree

‎extensions/lifecycle/tasks/LifecycleColdStatusArchiveTask.js‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,14 @@ class LifecycleColdStatusArchiveTask extends LifecycleUpdateTransitionTask {
108108
next => {
109109
const transitionTime = objectMD.getTransitionTime();
110110

111-
// set new ObjectMDArchive to ObjectMD
112-
objectMD.setArchive(new ObjectMDArchive(entry.archiveInfo));
111+
// set new ObjectMDArchive to ObjectMD, but make sure to keep any (deferred)
112+
// restore request
113+
const archive = objectMD.getArchive();
114+
objectMD.setArchive(new ObjectMDArchive(
115+
entry.archiveInfo,
116+
archive?.restoreRequestedAt,
117+
archive?.restoreRequestedDays,
118+
));
113119
objectMD.setOriginOp('s3:LifecycleTransition:SetArchive');
114120

115121
if (skipLocationDeletion) {

‎tests/unit/gc/GarbageCollectorTask.spec.js‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,12 @@ describe('GarbageCollectorTask', () => {
127127
mdObj.setLocation(loc)
128128
.setDataStoreName('old-location')
129129
.setAmzStorageClass('new-location')
130-
.setTransitionInProgress(true);
130+
.setTransitionInProgress(true)
131+
.setArchive({
132+
archiveInfo: { archiveId: 'da80b6dc-280d-4dce-83b5-d5b40276e321' },
133+
restoreRequestedAt: '2017-07-11T02:44:25.515Z',
134+
restoreRequestedDays: 3,
135+
});
131136
backbeatMetadataProxyClient.setMdObj(mdObj);
132137

133138
gcTask.processActionEntry(entry, err => {
@@ -137,6 +142,11 @@ describe('GarbageCollectorTask', () => {
137142
assert.strictEqual(updatedMD.getDataStoreName(), 'new-location');
138143
assert.strictEqual(updatedMD.getTransitionInProgress(), false);
139144
assert.strictEqual(updatedMD.getOriginOp(), 's3:LifecycleTransition:Direct');
145+
assert.deepStrictEqual(updatedMD.getArchive(), {
146+
archiveInfo: { archiveId: 'da80b6dc-280d-4dce-83b5-d5b40276e321' },
147+
restoreRequestedAt: '2017-07-11T02:44:25.515Z',
148+
restoreRequestedDays: 3,
149+
});
140150
done();
141151
});
142152
});

‎tests/unit/lifecycle/LifecycleColdStatusArchiveTask.spec.js‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,37 @@ describe('LifecycleColdStatusArchiveTask', () => {
165165
});
166166
});
167167

168+
it('should keep a restore requested during the archive window', done => {
169+
backbeatClient.batchDeleteResponse = { error: { statusCode: 404 }, res: null };
170+
171+
const entry = ColdStorageStatusQueueEntry.createFromKafkaEntry({ value: message });
172+
mdObj.setLocation()
173+
.setDataStoreName('us-east-1')
174+
.setAmzStorageClass(coldLocation);
175+
// setArchive() requires archiveInfo, which the object does not have yet
176+
mdObj.getValue().archive = {
177+
restoreRequestedAt: '2017-07-11T02:44:25.515Z',
178+
restoreRequestedDays: 3,
179+
};
180+
backbeatMetadataProxyClient.setMdObj(mdObj);
181+
182+
archiveTask.processEntry(coldLocation, entry, err => {
183+
assert.ifError(err);
184+
185+
const updatedMD = backbeatMetadataProxyClient.getReceivedMd();
186+
assert.strictEqual(updatedMD.originOp, 's3:LifecycleTransition:Direct');
187+
assert.deepStrictEqual(updatedMD.archive, {
188+
archiveInfo: {
189+
archiveId: 'da80b6dc-280d-4dce-83b5-d5b40276e321',
190+
archiveVersion: 5166759712787974,
191+
},
192+
restoreRequestedAt: '2017-07-11T02:44:25.515Z',
193+
restoreRequestedDays: 3,
194+
});
195+
done();
196+
});
197+
});
198+
168199
it('should send kafka entry to delete orphan cold object when source object was deleted', done => {
169200
const entry = ColdStorageStatusQueueEntry.createFromKafkaEntry({ value: message });
170201

0 commit comments

Comments
 (0)