-
Notifications
You must be signed in to change notification settings - Fork 259
fix putData : detect collision on specific provided version id #6230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: development/9.4
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ const backbeatProxy = httpProxy.createProxyServer({ | |
| }); | ||
| const { auth, errors, errorInstances, s3middleware, s3routes, models, storage, versioning } = require('arsenal'); | ||
| const { decode, encode } = versioning.VersionID; | ||
| const { ExternalNullVersionId } = versioning.VersioningConstants; | ||
| const { | ||
| VersionIdCollisionException, | ||
| StaleMicroVersionIdException, | ||
|
|
@@ -438,20 +439,21 @@ function putData(request, response, bucketInfo, objMd, log, callback) { | |
| } | ||
|
|
||
| const incomingVersionIdEncoded = request.headers['x-scal-version-id']; | ||
| if (incomingVersionIdEncoded !== undefined) { | ||
| const incomingVersionIdDecoded = | ||
| incomingVersionIdEncoded !== 'null' ? decode(incomingVersionIdEncoded) : 'null'; | ||
| if (incomingVersionIdDecoded instanceof Error) { | ||
| // ExternalNullVersionId means a pre-versioning null object: collision detection is not applicable. | ||
| if (incomingVersionIdEncoded !== undefined && incomingVersionIdEncoded !== ExternalNullVersionId) { | ||
| const decoded = decode(incomingVersionIdEncoded); | ||
| if (decoded instanceof Error) { | ||
| log.error('crr putData: failed to decode x-scal-version-id header', { | ||
| method: 'putData', | ||
| error: incomingVersionIdDecoded.message, | ||
| error: decoded.message, | ||
| }); | ||
| return callback( | ||
| errorInstances.BadRequest.customizeDescription('bad request: invalid x-scal-version-id header'), | ||
| ); | ||
| } | ||
| if (objMd && objMd.versionId === incomingVersionIdDecoded) { | ||
| // Data already at destination for this version; return 409 with the existing | ||
| if (objMd) { | ||
|
SylvainSenechal marked this conversation as resolved.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
const incomingVersionId = decode(incomingVersionIdEncoded);
// ... BadRequest on decode error ...
return metadataGetObject(request.bucketName, request.objectKey, incomingVersionId, null, log, (err, versionMd) => {
if (err) {
return callback(err);
}
if (versionMd) {
// existing 409 conflict path, using versionMd.microVersionId
}
return writeData();
}); |
||
| // objMd is the specific version (fetched by versionId from x-scal-version-id header) | ||
| // its existence means data is already at destination. Return 409 with the existing | ||
| // microVersionId so backbeat can decide if putMetadata is still needed. | ||
| log.debug('crr putData: version already at destination', { | ||
| method: 'putData', | ||
|
|
@@ -2069,7 +2071,20 @@ function routeBackbeat(clientIP, request, response, log) { | |
| }); | ||
| return next(errors.InvalidArgument); | ||
| } | ||
| const versionId = decodedVidResult; | ||
| let versionId = decodedVidResult; | ||
| // For putData api: the version to check is passed | ||
| // via x-scal-version-id header, not the URL query. Fetch that specific | ||
| // version so objMd matches the replicated version, not always the master. | ||
| const isPutDataApi = request.method === 'PUT' && request.resourceType === 'data'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The router shouldn't special-case one handler, and these guards duplicate putData's. Move the version lookup into putData itself (see handler comment) so this block goes away. |
||
| if (isPutDataApi) { | ||
| const versionIdHeader = request.headers['x-scal-version-id']; | ||
| if (versionIdHeader !== undefined && versionIdHeader !== ExternalNullVersionId) { | ||
| const decoded = decode(versionIdHeader); | ||
| if (!(decoded instanceof Error)) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Decode failure is ignore, should it be handled ? |
||
| versionId = decoded; | ||
| } | ||
| } | ||
| } | ||
| if (useMultipleBackend) { | ||
| if (request.resourceType === 'multiplebackendmetadata') { | ||
| return backbeatRoutes[request.method][request.resourceType](request, response, log, next); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for objMd.versionId === incomingVersionIdDecoded anymore as the middleware is already fetching objMd for the specific versionID provided in the header