Skip to content

Commit 69dbbb1

Browse files
Merge branch 'development/7.70' into improvement/ARSN-401-cluster-rpc-primary
2 parents 403c4e5 + 01409d6 commit 69dbbb1

File tree

3 files changed

+152
-14
lines changed

3 files changed

+152
-14
lines changed

lib/versioning/Version.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,6 @@ export class Version {
235235
return this;
236236
}
237237

238-
/**
239-
* Get the nullVersionId of the version.
240-
*
241-
* @return - the nullVersionId
242-
*/
243-
getNullVersionId(): string | undefined {
244-
return this.version.nullVersionId;
245-
}
246-
247238
/**
248239
* Mark a version as a delete marker.
249240
*

lib/versioning/VersioningRequestProcessor.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,8 @@ export default class VersioningRequestProcessor {
509509
if (request.options.isNull !== undefined && // new null key behavior when isNull is defined.
510510
masterVersion.isNullVersion() && // master is null
511511
!masterVersion.isNull2Version()) { // master does not support the new null key behavior yet.
512-
const masterNullVersionId = masterVersion.getNullVersionId();
513-
// The deprecated null key is referenced in the "nullVersionId" property of the master key.
512+
const masterNullVersionId = masterVersion.getVersionId();
513+
// The deprecated null key is referenced in the "versionId" property of the master key.
514514
if (masterNullVersionId) {
515515
const oldNullVersionKey = formatVersionKey(key, masterNullVersionId);
516516
ops.push({ key: oldNullVersionKey, type: 'del' });
@@ -561,8 +561,10 @@ export default class VersioningRequestProcessor {
561561
if (request.options.isNull === false) {
562562
masterVersion.setNull2Version();
563563
// else isNull === undefined means Cloudserver does not support null keys,
564+
// and versionIdFromMaster !== versionId means that a version is PUT on top of a null version
564565
// hence set/update the new master nullVersionId for backward compatibility
565-
} else {
566+
} else if (versionIdFromMaster !== versionId) {
567+
// => set the nullVersionId to the master version if put version on top of null version.
566568
value = Version.updateOrAppendNullVersionId(request.value, masterVersionId);
567569
}
568570
ops.push({ key: masterVersionKey,

tests/unit/versioning/VersioningRequestProcessor.spec.js

Lines changed: 147 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,70 @@ describe('test VRP', () => {
535535
done);
536536
});
537537

538+
it('should be able to update a null suspended version in backward compatibility mode', done => {
539+
let nullVersionId;
540+
541+
async.waterfall([next => {
542+
// simulate the creation of a null suspended version.
543+
const request = {
544+
db: 'foo',
545+
key: 'bar',
546+
value: '{"qux":"quz","isNull":true}',
547+
options: {
548+
versionId: '',
549+
},
550+
};
551+
vrp.put(request, logger, next);
552+
},
553+
(res, next) => {
554+
nullVersionId = JSON.parse(res).versionId;
555+
// simulate update null version with BackbeatClient.putMetadata
556+
const request = {
557+
db: 'foo',
558+
key: 'bar',
559+
value: `{"qux":"quz2","isNull":true,"versionId":"${nullVersionId}"}`,
560+
options: {
561+
versioning: true,
562+
versionId: nullVersionId,
563+
},
564+
};
565+
vrp.put(request, logger, next);
566+
},
567+
(res, next) => {
568+
wgm.list({}, logger, next);
569+
},
570+
(res, next) => {
571+
const expectedListing = [
572+
// NOTE: should not set nullVersionId to the master version if updating a null version.
573+
{
574+
key: 'bar',
575+
value: `{"qux":"quz2","isNull":true,"versionId":"${nullVersionId}"}`,
576+
},
577+
{
578+
key: `bar\x00${nullVersionId}`,
579+
value: `{"qux":"quz","isNull":true,"versionId":"${nullVersionId}"}`,
580+
},
581+
];
582+
assert.deepStrictEqual(res, expectedListing);
583+
584+
const request = {
585+
db: 'foo',
586+
key: 'bar',
587+
};
588+
vrp.get(request, logger, next);
589+
},
590+
(res, next) => {
591+
const expectedGet = {
592+
qux: 'quz2',
593+
isNull: true,
594+
versionId: nullVersionId,
595+
};
596+
assert.deepStrictEqual(JSON.parse(res), expectedGet);
597+
next();
598+
}],
599+
done);
600+
});
601+
538602
it('should delete the deprecated null key after put Metadata on top of an old null master', done => {
539603
const versionId = '00000000000000999999PARIS ';
540604
let nullVersionId;
@@ -592,8 +656,7 @@ describe('test VRP', () => {
592656
// the null key
593657
{
594658
key: `bar${VID_SEP}`,
595-
value: `{"qux":"quz2","isNull":true,"versionId":"${nullVersionId}",` +
596-
`"nullVersionId":"${nullVersionId}","isNull2":true}`,
659+
value: `{"qux":"quz2","isNull":true,"versionId":"${nullVersionId}","isNull2":true}`,
597660
},
598661
// version key
599662
{
@@ -691,6 +754,88 @@ describe('test VRP', () => {
691754
}],
692755
done);
693756
});
757+
758+
it('should delete the deprecated null key after updating a non-latest null key', done => {
759+
const versionId = '00000000000000999999PARIS ';
760+
let nullVersionId;
761+
762+
async.waterfall([next => {
763+
// simulate the creation of a null suspended version.
764+
const request = {
765+
db: 'foo',
766+
key: 'bar',
767+
value: '{"qux":"quz","isNull":true}',
768+
options: {
769+
versionId: '',
770+
},
771+
};
772+
vrp.put(request, logger, next);
773+
},
774+
(res, next) => {
775+
nullVersionId = JSON.parse(res).versionId;
776+
// simulate a BackbeatClient.putMetadata
777+
// null key is not the latest = master is not null.
778+
const request = {
779+
db: 'foo',
780+
key: 'bar',
781+
value: `{"qux":"quz2","versionId":"${versionId}"}`,
782+
options: {
783+
versioning: true,
784+
versionId,
785+
},
786+
};
787+
vrp.put(request, logger, next);
788+
},
789+
(res, next) => {
790+
// update the null version metadata with the new keys implementation (options.isNull defined)
791+
const request = {
792+
db: 'foo',
793+
key: 'bar',
794+
value: `{"qux":"quz3","isNull2":true,"isNull":true,"versionId":"${nullVersionId}"}`,
795+
options: {
796+
versionId: nullVersionId,
797+
isNull: true,
798+
},
799+
};
800+
vrp.put(request, logger, next);
801+
},
802+
(res, next) => {
803+
wgm.list({}, logger, next);
804+
},
805+
(res, next) => {
806+
const expectedListing = [
807+
{
808+
key: 'bar',
809+
value: `{"qux":"quz2","versionId":"${versionId}","nullVersionId":"${nullVersionId}"}`,
810+
},
811+
{
812+
key: 'bar\x00',
813+
value: `{"qux":"quz3","isNull2":true,"isNull":true,"versionId":"${nullVersionId}"}`,
814+
},
815+
{
816+
key: `bar\x00${versionId}`,
817+
value: `{"qux":"quz2","versionId":"${versionId}"}`,
818+
},
819+
];
820+
assert.deepStrictEqual(res, expectedListing);
821+
822+
const request = {
823+
db: 'foo',
824+
key: 'bar',
825+
};
826+
vrp.get(request, logger, next);
827+
},
828+
(res, next) => {
829+
const expectedGet = {
830+
qux: 'quz2',
831+
versionId,
832+
nullVersionId,
833+
};
834+
assert.deepStrictEqual(JSON.parse(res), expectedGet);
835+
next();
836+
}],
837+
done);
838+
});
694839
});
695840

696841

0 commit comments

Comments
 (0)