Compare commits

...

3 Commits

Author SHA1 Message Date
Jonathan Gramain 4cd1b53461 [hotfix] UTAPI-82 UTAPI-87 bump version to 7.10.7-1 2022-11-11 11:34:20 -08:00
Taylor McKinnon 6a31285faf bf(UTAPI-87): Handle deleting zero byte objects in version suspended buckets
(cherry picked from commit c3111dfadf)
2022-11-11 11:32:48 -08:00
Artem Bakalov 1636b371dc UTAPI-82 fix delete inconsistency
(cherry picked from commit 193d1a5d92)
2022-11-11 11:32:30 -08:00
3 changed files with 79 additions and 2 deletions

View File

@ -546,7 +546,9 @@ class UtapiClient {
if (this._isCounterEnabled(counterAction)) { if (this._isCounterEnabled(counterAction)) {
cmds.push(['incr', generateKey(p, counterAction, timestamp)]); cmds.push(['incr', generateKey(p, counterAction, timestamp)]);
} }
cmds.push(['zrangebyscore', generateStateKey(p, 'storageUtilized'), timestamp, timestamp]);
}); });
return this.ds.batch(cmds, (err, results) => { return this.ds.batch(cmds, (err, results) => {
if (err) { if (err) {
log.error('error pushing metric', { log.error('error pushing metric', {
@ -580,13 +582,48 @@ class UtapiClient {
// empty. // empty.
actionCounter = Number.isNaN(actionCounter) actionCounter = Number.isNaN(actionCounter)
|| actionCounter < 0 ? 1 : actionCounter; || actionCounter < 0 ? 1 : actionCounter;
if (Number.isInteger(params.byteLength)) {
/* byteLength is passed in from cloudserver under the follow conditions:
* - bucket versioning is suspended
* - object version id is null
* - the content length of the object exists
* In this case, the master key is deleted and replaced with a delete marker.
* The decrement accounts for the deletion of the master key when utapi reports
* on the number of objects.
*/
actionCounter -= 1;
}
const key = generateStateKey(p, 'numberOfObjects'); const key = generateStateKey(p, 'numberOfObjects');
const byteArr = results[index + commandsGroupSize - 1][1];
const oldByteLength = byteArr ? parseInt(byteArr[0], 10) : 0;
const newByteLength = member.serialize(Math.max(0, oldByteLength - params.byteLength));
cmds2.push( cmds2.push(
['zremrangebyscore', key, timestamp, timestamp], ['zremrangebyscore', key, timestamp, timestamp],
['zadd', key, timestamp, member.serialize(actionCounter)], ['zadd', key, timestamp, member.serialize(actionCounter)],
); );
if (Number.isInteger(params.byteLength)) {
cmds2.push(
['decr', generateCounter(p, 'numberOfObjectsCounter')],
['decrby', generateCounter(p, 'storageUtilizedCounter'), params.byteLength],
);
}
if (byteArr) {
cmds2.push(
['zremrangebyscore', generateStateKey(p, 'storageUtilized'), timestamp, timestamp],
['zadd', generateStateKey(p, 'storageUtilized'), timestamp, newByteLength],
);
}
return true; return true;
}); });
if (noErr) { if (noErr) {
return this.ds.batch(cmds2, cb); return this.ds.batch(cmds2, cb);
} }

View File

@ -3,7 +3,7 @@
"engines": { "engines": {
"node": ">=16" "node": ">=16"
}, },
"version": "7.10.7", "version": "7.10.7-1",
"description": "API for tracking resource utilization and reporting metrics", "description": "API for tracking resource utilization and reporting metrics",
"main": "index.js", "main": "index.js",
"repository": { "repository": {

View File

@ -247,7 +247,11 @@ tests.forEach(test => {
c.setDataStore(ds); c.setDataStore(ds);
c.pushMetric(metric, REQUID, params, () => { c.pushMetric(metric, REQUID, params, () => {
deserializeMemoryBackend(memoryBackend.data); deserializeMemoryBackend(memoryBackend.data);
assert.deepStrictEqual(memoryBackend.data, expected); Object.keys(expected).forEach(key => {
if (memoryBackend.data[key]) {
assert.deepStrictEqual(memoryBackend.data[key], expected[key]);
}
});
return cb(); return cb();
}); });
} }
@ -490,6 +494,7 @@ tests.forEach(test => {
storageUtilized: '1024', storageUtilized: '1024',
numberOfObjects: '1', numberOfObjects: '1',
}; };
setMockData(data, timestamp, () => { setMockData(data, timestamp, () => {
testMetric('deleteObject', params, expected, done); testMetric('deleteObject', params, expected, done);
}); });
@ -667,6 +672,40 @@ tests.forEach(test => {
testMetric('putDeleteMarkerObject', metricTypes, expected, done); testMetric('putDeleteMarkerObject', metricTypes, expected, done);
}); });
it('should push putDeleteMarkerObject metrics and have correct bytes and number of objects', done => {
const expected = buildExpectedResult({
action: 'PutObject',
numberOfObjects: '1',
});
const metrics = {
bucket: '5741-repro',
keys: ['foo2'],
byteLength: undefined,
newByteLength: 258,
oldByteLength: null,
numberOfObjects: 1,
accountId: '79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be',
userId: undefined,
};
testMetric('putObject', Object.assign(metrics, metricTypes), expected, () => {
const expected = buildExpectedResult({
action: 'DeleteObject',
numberOfObjects: '1',
});
const metrics2 = {
bucket: '5741-repro',
keys: ['foo2'],
byteLength: 258,
newByteLength: undefined,
oldByteLength: undefined,
numberOfObjects: undefined,
accountId: '79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be',
userId: undefined,
};
testMetric('putDeleteMarkerObject', Object.assign(metrics2, metricTypes), expected, done);
});
});
it('should push putBucketReplication metrics', done => { it('should push putBucketReplication metrics', done => {
const expected = buildExpectedResult({ const expected = buildExpectedResult({
action: 'PutBucketReplication', action: 'PutBucketReplication',
@ -766,3 +805,4 @@ tests.forEach(test => {
}); });
}); });
}); });