Compare commits

...

3 Commits

Author SHA1 Message Date
Jonathan Gramain 7293f93c22 ARSN-296 bump hotfix version to 7.10.36-1 2023-01-25 20:22:55 +01:00
Jonathan Gramain 7828235056 ARSN-296 Revert "ARSN-252 - listing bug in DelimisterMaster"
This reverts commit 5f0df14ca8.

(cherry picked from commit cb31a07d8d)
2023-01-25 20:22:31 +01:00
Jonathan Gramain ad45f05bbd ARSN-296 Revert "ARSN-269 - listing bug in versioned bucket edge cases."
This reverts commit 88f16366a1.

(cherry picked from commit 62be7f926d)
2023-01-25 20:22:31 +01:00
5 changed files with 9 additions and 377 deletions

View File

@ -271,4 +271,4 @@ class Delimiter extends Extension {
} }
} }
module.exports = { Delimiter, getCommonPrefix }; module.exports = { Delimiter };

View File

@ -33,8 +33,6 @@ class DelimiterMaster extends Delimiter {
this.prvKey = undefined; this.prvKey = undefined;
this.prvPHDKey = undefined; this.prvPHDKey = undefined;
this.inReplayPrefix = false; this.inReplayPrefix = false;
this.prefixKeySeen = false;
this.prefixEndsWithDelim = this.prefix && this.prefix.endsWith(this.delimiter);
Object.assign(this, { Object.assign(this, {
[BucketVersioningKeyFormat.v0]: { [BucketVersioningKeyFormat.v0]: {
@ -64,10 +62,6 @@ class DelimiterMaster extends Delimiter {
let key = obj.key; let key = obj.key;
const value = obj.value; const value = obj.value;
if (key === this.prefix) {
this.prefixKeySeen = true;
}
if (key.startsWith(DbPrefixes.Replay)) { if (key.startsWith(DbPrefixes.Replay)) {
this.inReplayPrefix = true; this.inReplayPrefix = true;
return FILTER_SKIP; return FILTER_SKIP;
@ -101,8 +95,9 @@ class DelimiterMaster extends Delimiter {
* NextMarker to the common prefix instead of the whole key * NextMarker to the common prefix instead of the whole key
* value. (TODO: remove this test once ZENKO-1048 is fixed) * value. (TODO: remove this test once ZENKO-1048 is fixed)
* */ * */
if (key === this.prvKey || key === this[this.nextContinueMarker] if (key === this.prvKey || key === this[this.nextContinueMarker] ||
|| (this.delimiter && key.startsWith(this[this.nextContinueMarker]))) { (this.delimiter &&
key.startsWith(this[this.nextContinueMarker]))) {
/* master version already filtered */ /* master version already filtered */
return FILTER_SKIP; return FILTER_SKIP;
} }
@ -132,14 +127,6 @@ class DelimiterMaster extends Delimiter {
return FILTER_ACCEPT; return FILTER_ACCEPT;
} }
this.prvKey = key; this.prvKey = key;
if (this.prefixEndsWithDelim) {
/* When the prefix ends with a delimiter, update nextContinueMarker
* to be able to skip ranges of the form prefix/subprefix/ as an optimization.
* The marker may also end up being prefix/, in which case .skipping will determine
* if a skip over the full range is allowed or a smaller skipping range of prefix/{VID_SEP}
* must be used. */
this[this.nextContinueMarker] = key.slice(0, key.lastIndexOf(this.delimiter) + 1);
}
return FILTER_SKIP; return FILTER_SKIP;
} }
@ -175,27 +162,6 @@ class DelimiterMaster extends Delimiter {
return super.filter(obj); return super.filter(obj);
} }
/**
* Determine if a nextContinueMarker ending with a delimiter
* can be skipped.
* @returns {bool}
*/
allowDelimiterRangeSkip() {
if (!this.prefixKeySeen) {
// A prefix key is a master key equal to the prefix. If it has
// not been encountered, can skip.
return true;
}
const marker = this[this.nextContinueMarker];
// prefix = prefix, key = prefix/. Can skip since key will be part of commonPrefixes.
if (marker.length > this.prefix.length && marker.startsWith(this.prefix)) {
return true;
}
const lastIdx = marker.lastIndexOf(this.delimiter); // prefix/foo is a masterKey following a prefix key.
return marker.slice(0, lastIdx + 1) !== this.prefix; // cannot skip the full range prefix/ range.
}
skippingBase() { skippingBase() {
if (this[this.nextContinueMarker]) { if (this[this.nextContinueMarker]) {
// next marker or next continuation token: // next marker or next continuation token:
@ -203,7 +169,7 @@ class DelimiterMaster extends Delimiter {
// - foo : skipping foo. // - foo : skipping foo.
const index = this[this.nextContinueMarker]. const index = this[this.nextContinueMarker].
lastIndexOf(this.delimiter); lastIndexOf(this.delimiter);
if (index === this[this.nextContinueMarker].length - 1 && this.allowDelimiterRangeSkip()) { if (index === this[this.nextContinueMarker].length - 1) {
return this[this.nextContinueMarker]; return this[this.nextContinueMarker];
} }
return this[this.nextContinueMarker] + VID_SEP; return this[this.nextContinueMarker] + VID_SEP;

View File

@ -3,7 +3,7 @@
"engines": { "engines": {
"node": ">=16" "node": ">=16"
}, },
"version": "7.10.36", "version": "7.10.36-1",
"description": "Common utilities for the S3 project components", "description": "Common utilities for the S3 project components",
"main": "build/index.js", "main": "build/index.js",
"repository": { "repository": {
@ -62,7 +62,6 @@
"@types/jest": "^27.4.1", "@types/jest": "^27.4.1",
"@types/node": "^17.0.21", "@types/node": "^17.0.21",
"@types/xml2js": "^0.4.11", "@types/xml2js": "^0.4.11",
"chance": "^1.1.8",
"eslint": "^8.12.0", "eslint": "^8.12.0",
"eslint-config-airbnb": "6.2.0", "eslint-config-airbnb": "6.2.0",
"eslint-config-scality": "scality/Guidelines#7.10.2", "eslint-config-scality": "scality/Guidelines#7.10.2",

View File

@ -1,7 +1,7 @@
'use strict'; // eslint-disable-line strict 'use strict'; // eslint-disable-line strict
const assert = require('assert'); const assert = require('assert');
const chance = require('chance').Chance(); // eslint-disable-line
const DelimiterMaster = const DelimiterMaster =
require('../../../../lib/algos/list/delimiterMaster').DelimiterMaster; require('../../../../lib/algos/list/delimiterMaster').DelimiterMaster;
const { const {
@ -16,6 +16,8 @@ const Version = require('../../../../lib/versioning/Version').Version;
const { generateVersionId } = require('../../../../lib/versioning/VersionID'); const { generateVersionId } = require('../../../../lib/versioning/VersionID');
const { DbPrefixes } = VSConst; const { DbPrefixes } = VSConst;
const zpad = require('../../helpers').zpad; const zpad = require('../../helpers').zpad;
const VID_SEP = VSConst.VersionId.Separator; const VID_SEP = VSConst.VersionId.Separator;
const EmptyResult = { const EmptyResult = {
CommonPrefixes: [], CommonPrefixes: [],
@ -486,336 +488,6 @@ function getListingKey(key, vFormat) {
// ...it should return to skipping by prefix as usual // ...it should return to skipping by prefix as usual
assert.strictEqual(delimiter.skipping(), `${inc(DbPrefixes.Replay)}foo/`); assert.strictEqual(delimiter.skipping(), `${inc(DbPrefixes.Replay)}foo/`);
}); });
it('should not skip over whole prefix when a key equals the prefix and ends with delimiter', () => {
for (const prefix of ['prefix/', 'prefix/subprefix/']) {
const delimiter = new DelimiterMaster({
prefix,
delimiter: '/',
}, fakeLogger, vFormat);
for (const testEntry of [
{
key: prefix,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}${VID_SEP}v1`,
value: '{}',
expectedRes: FILTER_SKIP, // versions get skipped after master
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}deleted`,
isDeleteMarker: true,
expectedRes: FILTER_SKIP, // delete markers get skipped
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}deleted${VID_SEP}v1`,
isDeleteMarker: true,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}deleted${VID_SEP}v2`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}notdeleted`,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}notdeleted${VID_SEP}`,
},
{
key: `${prefix}notdeleted${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}notdeleted${VID_SEP}`,
},
{
key: `${prefix}subprefix1/key-1`,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}subprefix1/`,
},
{
key: `${prefix}subprefix1/key-1${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}subprefix1/`,
},
{
key: `${prefix}subprefix1/key-2`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}subprefix1/`,
},
{
key: `${prefix}subprefix1/key-2${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}subprefix1/`,
},
]) {
const entry = {
key: testEntry.key,
};
if (testEntry.isDeleteMarker) {
entry.value = '{"isDeleteMarker":true}';
} else {
entry.value = '{}';
}
const res = delimiter.filter(entry);
const skipping = delimiter.skipping();
assert.strictEqual(res, testEntry.expectedRes);
assert.strictEqual(skipping, testEntry.expectedSkipping);
}
}
});
it('should skip over whole prefix when a key equals the prefix and does not end with delimiter', () => {
for (const prefix of ['prefix', 'prefix/subprefix']) {
const delimiter = new DelimiterMaster({
prefix,
delimiter: '/',
}, fakeLogger, vFormat);
for (const testEntry of [
{
key: prefix,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}/`,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}/`,
},
{
key: `${prefix}/${VID_SEP}v1`,
value: '{}',
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}/`, // common prefix already seen
},
{
key: `${prefix}/deleted`,
isDeleteMarker: true, // skipped delete marker
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}/`, // already added to common prefix
},
{
key: `${prefix}/notdeleted`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}/`, // already added to common prefix
},
{
key: `${prefix}ed`,
isDeleteMarker: false,
expectedRes: FILTER_ACCEPT, // new master key seen
expectedSkipping: `${prefix}ed${VID_SEP}`,
},
{
key: `${prefix}ed/`,
expectedRes: FILTER_ACCEPT, // new master key ending with prefix
expectedSkipping: `${prefix}ed/`,
},
{
key: `${prefix}ed/subprefix1/key-1`,
expectedRes: FILTER_SKIP, // already have prefixed/ common prefix
expectedSkipping: `${prefix}ed/`,
},
{
key: `${prefix}ed/subprefix1/key-1${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}ed/`,
},
{
key: `${prefix}ed/subprefix1/key-2`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}ed/`,
},
{
key: `${prefix}ed/subprefix1/key-2${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}ed/`,
},
]) {
const entry = {
key: testEntry.key,
};
if (testEntry.isDeleteMarker) {
entry.value = '{"isDeleteMarker":true}';
} else {
entry.value = '{}';
}
const res = delimiter.filter(entry);
const skipping = delimiter.skipping();
assert.strictEqual(res, testEntry.expectedRes);
assert.strictEqual(skipping, testEntry.expectedSkipping);
}
}
});
it('should not skip over whole prefix when key equals the prefix and prefix key has delete marker ' +
'and prefix ends with delimiter', () => {
for (const prefix of ['prefix/', 'prefix/subprefix/']) {
const delimiter = new DelimiterMaster({
prefix,
delimiter: '/',
}, fakeLogger, vFormat);
for (const testEntry of [
{
key: prefix,
isDeleteMarker: true,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}subprefix-1`,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}subprefix-1${VID_SEP}`,
},
{
key: `${prefix}subprefix-1/foo`,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}subprefix-1/`,
},
{
key: `${prefix}subprefix-1/bar`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}subprefix-1/`, // already added to common prefix
},
]) {
const entry = {
key: testEntry.key,
};
if (testEntry.isDeleteMarker) {
entry.value = '{"isDeleteMarker":true}';
} else {
entry.value = '{}';
}
const res = delimiter.filter(entry);
const skipping = delimiter.skipping();
assert.strictEqual(res, testEntry.expectedRes);
assert.strictEqual(skipping, testEntry.expectedSkipping);
}
}
});
it('should skip over whole prefix when key equals the prefix, prefix key has delete marker ' +
'and prefix does not end with delimiter', () => {
for (const prefix of ['prefix', 'prefix/subprefix']) {
const delimiter = new DelimiterMaster({
prefix,
delimiter: '/',
}, fakeLogger, vFormat);
for (const testEntry of [
{
key: prefix,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}${VID_SEP}v1`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}/`,
isDeleteMarker: true,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}/subprefix-1`,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}/`,
},
{
key: `${prefix}/subprefix-1/foo`,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}/`,
},
{
key: `${prefix}aa`,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}aa${VID_SEP}`, // already added to common prefix
},
]) {
const entry = {
key: testEntry.key,
};
if (testEntry.isDeleteMarker) {
entry.value = '{"isDeleteMarker":true}';
} else {
entry.value = '{}';
}
const res = delimiter.filter(entry);
const skipping = delimiter.skipping();
assert.strictEqual(res, testEntry.expectedRes);
assert.strictEqual(skipping, testEntry.expectedSkipping);
}
}
});
it('should be able to skip subprefixes within deleteMarker keys when a prefix key ' +
'ending with delimiter is seen', () => {
for (const prefix of ['prefix/', 'prefix/subprefix/']) {
const delimiter = new DelimiterMaster({
prefix,
delimiter: '/',
}, fakeLogger, vFormat);
for (const testEntry of [
{
key: prefix,
expectedRes: FILTER_ACCEPT,
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}${VID_SEP}v1`,
// isDeleteMarker: true,
expectedRes: FILTER_SKIP, // versions get skipped after master
expectedSkipping: `${prefix}${VID_SEP}`,
},
{
key: `${prefix}foo/`,
isDeleteMarker: true,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}foo/`,
},
{
key: `${prefix}foo/1`,
isDeleteMarker: true,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}foo/`,
},
{
key: `${prefix}foo/2`,
isDeleteMarker: true,
expectedRes: FILTER_SKIP,
expectedSkipping: `${prefix}foo/`,
},
]) {
const entry = {
key: testEntry.key,
};
if (testEntry.isDeleteMarker) {
entry.value = '{"isDeleteMarker":true}';
} else {
entry.value = '{}';
}
const res = delimiter.filter(entry);
const skipping = delimiter.skipping();
assert.strictEqual(res, testEntry.expectedRes);
assert.strictEqual(skipping, testEntry.expectedSkipping);
}
}
});
} }
}); });
}); });

View File

@ -2144,11 +2144,6 @@ chalk@^4.0.0:
ansi-styles "^4.1.0" ansi-styles "^4.1.0"
supports-color "^7.1.0" supports-color "^7.1.0"
chance@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.8.tgz#5d6c2b78c9170bf6eb9df7acdda04363085be909"
integrity sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg==
char-regex@^1.0.2: char-regex@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"