Compare commits
4 Commits
developmen
...
bugfix/rep
Author | SHA1 | Date |
---|---|---|
Nicolas Humbert | 890c0815e3 | |
Nicolas Humbert | 6f2c5362bf | |
Nicolas Humbert | 9af111f1b8 | |
Nicolas Humbert | 448b2fee06 |
|
@ -1,4 +1,5 @@
|
||||||
export { default as ARN } from './ARN';
|
export { default as ARN } from './ARN';
|
||||||
|
export { default as BackendInfo } from './BackendInfo';
|
||||||
export { default as BucketInfo } from './BucketInfo';
|
export { default as BucketInfo } from './BucketInfo';
|
||||||
export { default as ObjectMD } from './ObjectMD';
|
export { default as ObjectMD } from './ObjectMD';
|
||||||
export { default as ObjectMDLocation } from './ObjectMDLocation';
|
export { default as ObjectMDLocation } from './ObjectMDLocation';
|
||||||
|
|
|
@ -103,6 +103,27 @@ export class Version {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static updateOrAppendNullVersionId(value: string, nullVersionId: string): string {
|
||||||
|
// Check if "nullVersionId" already exists in the string
|
||||||
|
const nullVersionIdPattern = /"nullVersionId":"[^"]*"/;
|
||||||
|
const nullVersionIdExists = nullVersionIdPattern.test(value);
|
||||||
|
|
||||||
|
if (nullVersionIdExists) {
|
||||||
|
// Replace the existing nullVersionId with the new one
|
||||||
|
return value.replace(nullVersionIdPattern, `"nullVersionId":"${nullVersionId}"`);
|
||||||
|
} else {
|
||||||
|
// Append nullVersionId in the cheap way as before
|
||||||
|
let index = value.length - 2;
|
||||||
|
while (value.charAt(index--) === ' ');
|
||||||
|
const comma = value.charAt(index + 1) !== '{';
|
||||||
|
return (
|
||||||
|
`${value.slice(0, value.length - 1)}` + // eslint-disable-line
|
||||||
|
(comma ? ',' : '') +
|
||||||
|
`"nullVersionId":"${nullVersionId}"}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [MetaData Internal] Check if a version is a place holder for deletion.
|
* [MetaData Internal] Check if a version is a place holder for deletion.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import errors, { ArsenalError } from '../errors';
|
import errors, { ArsenalError } from '../errors';
|
||||||
import { Version } from './Version';
|
import { Version } from './Version';
|
||||||
import { generateVersionId as genVID } from './VersionID';
|
import { generateVersionId as genVID, getInfVid } from './VersionID';
|
||||||
import WriteCache from './WriteCache';
|
import WriteCache from './WriteCache';
|
||||||
import WriteGatheringManager from './WriteGatheringManager';
|
import WriteGatheringManager from './WriteGatheringManager';
|
||||||
|
|
||||||
|
@ -291,6 +291,7 @@ export default class VersioningRequestProcessor {
|
||||||
// also update master version in case the put
|
// also update master version in case the put
|
||||||
// version is newer or same version than master.
|
// version is newer or same version than master.
|
||||||
// if versionId === '' update master version
|
// if versionId === '' update master version
|
||||||
|
console.log('options!!!', options);
|
||||||
const versioning = options &&
|
const versioning = options &&
|
||||||
(options.versioning || options.versioning === '');
|
(options.versioning || options.versioning === '');
|
||||||
const versionId = options &&
|
const versionId = options &&
|
||||||
|
@ -380,12 +381,47 @@ export default class VersioningRequestProcessor {
|
||||||
const versionId = request.options.versionId;
|
const versionId = request.options.versionId;
|
||||||
const versionKey = formatVersionKey(request.key, versionId);
|
const versionKey = formatVersionKey(request.key, versionId);
|
||||||
const ops = [{ key: versionKey, value: request.value }];
|
const ops = [{ key: versionKey, value: request.value }];
|
||||||
if (data === undefined ||
|
const masterVersion = data !== undefined &&
|
||||||
(Version.from(data).getVersionId() ?? '') >= versionId) {
|
Version.from(data);
|
||||||
// master does not exist or is not newer than put
|
if (masterVersion) {
|
||||||
// version and needs to be updated as well.
|
const versionIdFromMaster = masterVersion.getVersionId();
|
||||||
// Note that older versions have a greater version ID.
|
// master key exists
|
||||||
ops.push({ key: request.key, value: request.value });
|
console.log('MASTER EXIST!!!');
|
||||||
|
console.log('versionIdFromMaster!!!', versionIdFromMaster);
|
||||||
|
console.log('versionId!!!', versionId);
|
||||||
|
if (versionIdFromMaster === undefined ||
|
||||||
|
versionIdFromMaster >= versionId) {
|
||||||
|
console.log('MASTER CREATED!!!!');
|
||||||
|
// master key is not newer than the put version
|
||||||
|
let masterVersionId;
|
||||||
|
let value = request.value;
|
||||||
|
console.log('masterVersion!!!', masterVersion);
|
||||||
|
if (masterVersion.isNullVersion() && versionIdFromMaster) {
|
||||||
|
// master key is a null version
|
||||||
|
masterVersionId = versionIdFromMaster;
|
||||||
|
} else if (versionIdFromMaster === undefined) {
|
||||||
|
// master key does not have a versionID
|
||||||
|
// => create one with the "infinite" version ID
|
||||||
|
masterVersionId = getInfVid(this.replicationGroupId);
|
||||||
|
masterVersion.setVersionId(masterVersionId);
|
||||||
|
}
|
||||||
|
if (masterVersionId) {
|
||||||
|
// => create a new version key from the master version
|
||||||
|
const masterVersionKey = formatVersionKey(key, masterVersionId);
|
||||||
|
value = Version.updateOrAppendNullVersionId(request.value, masterVersionId);
|
||||||
|
masterVersion.setNullVersion();
|
||||||
|
console.log('masterVersionId!!!', masterVersionId);
|
||||||
|
ops.push({ key: masterVersionKey,
|
||||||
|
value: masterVersion.toString() });
|
||||||
|
}
|
||||||
|
// => update the master key, note that older
|
||||||
|
// versions have a greater version ID
|
||||||
|
ops.push({ key, value });
|
||||||
|
}
|
||||||
|
// otherwise, master key is newer so do not update it
|
||||||
|
} else {
|
||||||
|
// master key does not exist: create it
|
||||||
|
ops.push({ key, value: request.value });
|
||||||
}
|
}
|
||||||
return callback(null, ops, versionId);
|
return callback(null, ops, versionId);
|
||||||
});
|
});
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
"lint": "eslint $(git ls-files '*.js')",
|
"lint": "eslint $(git ls-files '*.js')",
|
||||||
"lint_md": "mdlint $(git ls-files '*.md')",
|
"lint_md": "mdlint $(git ls-files '*.md')",
|
||||||
"lint_yml": "yamllint $(git ls-files '*.yml')",
|
"lint_yml": "yamllint $(git ls-files '*.yml')",
|
||||||
"test": "jest tests/unit",
|
"test": "jest tests/unit/versioning/VersioningRequestProcessor.spec.js",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"prepare": "yarn build",
|
"prepare": "yarn build",
|
||||||
"ft_test": "jest tests/functional --testTimeout=120000 --forceExit",
|
"ft_test": "jest tests/functional --testTimeout=120000 --forceExit",
|
||||||
|
|
|
@ -219,4 +219,140 @@ describe('test VSP', () => {
|
||||||
}],
|
}],
|
||||||
done);
|
done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should be able to put Metadata on top of a null version', done => {
|
||||||
|
const versionId = '00000000000000999999PARIS ';
|
||||||
|
|
||||||
|
async.waterfall([next => {
|
||||||
|
const request = {
|
||||||
|
db: 'foo',
|
||||||
|
key: 'bar',
|
||||||
|
value: '{"qux":"quz"}',
|
||||||
|
options: {},
|
||||||
|
};
|
||||||
|
vsp.put(request, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
const request = {
|
||||||
|
db: 'foo',
|
||||||
|
key: 'bar',
|
||||||
|
value: `{"qux":"quz2","versionId":"${versionId}"}`,
|
||||||
|
options: {
|
||||||
|
isNull: false,
|
||||||
|
versioning: true,
|
||||||
|
versionId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vsp.put(request, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
wgm.list({}, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
const expectedListing = [
|
||||||
|
// master version should have the provided version id and a reference of the null version id.
|
||||||
|
{
|
||||||
|
key: 'bar',
|
||||||
|
value: `{"qux":"quz2","versionId":"${versionId}","nullVersionId":"99999999999999999999PARIS "}`
|
||||||
|
},
|
||||||
|
// the "internal" master version should have the provided version id.
|
||||||
|
{
|
||||||
|
key: `bar\x00${versionId}`,
|
||||||
|
value: `{"qux":"quz2","versionId":"${versionId}"}`,
|
||||||
|
},
|
||||||
|
// should create a version that represents the old null master with the infinite version id and
|
||||||
|
// the isNull property set to true.
|
||||||
|
{
|
||||||
|
key: 'bar\x0099999999999999999999PARIS ',
|
||||||
|
value: '{"qux":"quz","versionId":"99999999999999999999PARIS ","isNull":true}'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
assert.deepStrictEqual(res, expectedListing);
|
||||||
|
const request = {
|
||||||
|
db: 'foo',
|
||||||
|
key: 'bar',
|
||||||
|
};
|
||||||
|
vsp.get(request, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
const expectedGet = {
|
||||||
|
qux: 'quz2',
|
||||||
|
versionId,
|
||||||
|
nullVersionId: '99999999999999999999PARIS ',
|
||||||
|
};
|
||||||
|
assert.deepStrictEqual(JSON.parse(res), expectedGet);
|
||||||
|
next();
|
||||||
|
}],
|
||||||
|
done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to put Metadata on top of a null suspended version', done => {
|
||||||
|
const versionId = '00000000000000999999PARIS ';
|
||||||
|
let nullVersionId;
|
||||||
|
|
||||||
|
async.waterfall([next => {
|
||||||
|
const request = {
|
||||||
|
db: 'foo',
|
||||||
|
key: 'bar',
|
||||||
|
value: '{"qux":"quz","isNull":true}',
|
||||||
|
options: {
|
||||||
|
versionId: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vsp.put(request, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
nullVersionId = JSON.parse(res).versionId;
|
||||||
|
const request = {
|
||||||
|
db: 'foo',
|
||||||
|
key: 'bar',
|
||||||
|
value: `{"qux":"quz2","versionId":"${versionId}"}`,
|
||||||
|
options: {
|
||||||
|
isNull: false,
|
||||||
|
versioning: true,
|
||||||
|
versionId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
vsp.put(request, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
wgm.list({}, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
const expectedListing = [
|
||||||
|
// master version should have the provided version id and a reference of the null version id.
|
||||||
|
{
|
||||||
|
key: 'bar',
|
||||||
|
value: `{"qux":"quz2","versionId":"${versionId}","nullVersionId":"${nullVersionId}"}`
|
||||||
|
},
|
||||||
|
// the "internal" master version should have the provided version id.
|
||||||
|
{
|
||||||
|
key: `bar\x00${versionId}`,
|
||||||
|
value: `{"qux":"quz2","versionId":"${versionId}"}`,
|
||||||
|
},
|
||||||
|
// should create a version that represents the old null master with the infinite version id and
|
||||||
|
// the isNull property set to true.
|
||||||
|
{
|
||||||
|
key: `bar\x00${nullVersionId}`,
|
||||||
|
value: `{"qux":"quz","isNull":true,"versionId":"${nullVersionId}"}`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
assert.deepStrictEqual(res, expectedListing);
|
||||||
|
const request = {
|
||||||
|
db: 'foo',
|
||||||
|
key: 'bar',
|
||||||
|
};
|
||||||
|
vsp.get(request, logger, next);
|
||||||
|
},
|
||||||
|
(res, next) => {
|
||||||
|
const expectedGet = {
|
||||||
|
qux: 'quz2',
|
||||||
|
versionId,
|
||||||
|
nullVersionId,
|
||||||
|
};
|
||||||
|
assert.deepStrictEqual(JSON.parse(res), expectedGet);
|
||||||
|
next();
|
||||||
|
}],
|
||||||
|
done);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue