Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
NativeIO: Add quota to sync Blink interface
This CL adds implements NativeIO's quota management system for
synchronous calls in Blink.

Blink requests capacity from the browser process. This CL does not
change how capacity is granted by the browser process. The IPC call to
the browser for requesting capacity is synchronous if and only if
NativeIO's synchronous interface is being used.

The design doc for NativeIO's quota system is here:
https://docs.google.com/document/d/1wUrtCOsyH3qGwKuqLhV9AJD-bDAjAzfPL5r1GT8H4IY

Bug: 1137788
Change-Id: If306e77bdaa66e34c28a633601608de307875c67
  • Loading branch information
rstz authored and chromium-wpt-export-bot committed Feb 25, 2021
1 parent 50adeb0 commit 4448bdc
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 70 deletions.
38 changes: 38 additions & 0 deletions native-io/capacity_allocation_sync_basic.tentative.https.any.js
@@ -0,0 +1,38 @@
// META: title=NativeIO API: Acquiring, displaying and releasing capacity.
// META: global=dedicatedworker

'use strict';

test(testCase => {
const available_capacity = storageFoundation.getRemainingCapacitySync();
assert_equals(available_capacity, 0);
}, 'The starting capacity of a NativeIOFileManager is 0');

test(testCase => {
const requested_capacity = 4;
const granted_capacity = storageFoundation.requestCapacitySync(requested_capacity);
const available_capacity = storageFoundation.getRemainingCapacitySync();
assert_equals(available_capacity, granted_capacity);
testCase.add_cleanup(() => {
storageFoundation.releaseCapacitySync(available_capacity);
});
}, 'getRemainingCapacitySync() reports the capacity granted by ' +
'requestCapacitySync()');

test(testCase => {
const requested_capacity = 4;
const granted_capacity = storageFoundation.requestCapacitySync(requested_capacity);
storageFoundation.releaseCapacitySync(granted_capacity);
const available_capacity = storageFoundation.getRemainingCapacitySync();
assert_equals(available_capacity, 0);
}, 'getRemainingCapacitySync() reports zero after a releaseCapacitySync() ' +
'matching the capacity granted by a requestCapacitySync().');

test(testCase => {
const requested_capacity = 4;
const granted_capacity = storageFoundation.requestCapacitySync(requested_capacity);
assert_greater_than_equal(granted_capacity, requested_capacity);
testCase.add_cleanup(() => {
storageFoundation.releaseCapacitySync(granted_capacity);
});
}, 'requestCapacitySync() grants the requested capacity for small requests');
30 changes: 13 additions & 17 deletions native-io/close_sync.tentative.https.any.js
@@ -1,33 +1,21 @@
// META: title=Synchronous NativeIO API: close().
// META: global=dedicatedworker
// META: script=resources/support.js

'use strict';

// Returns a handle to a newly created file that holds some data.
//
// The file will be closed and deleted when the test ends.
function createFileSync(testCase, fileName) {
const file = storageFoundation.openSync(fileName);
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync(fileName);
});

const writtenBytes = Uint8Array.from([64, 65, 66, 67]);
const writeCount = file.write(writtenBytes, 0);
assert_equals(writeCount, 4);

return file;
}

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, 'file_name');
assert_equals(undefined, file.close());

assert_equals(undefined, file.close());
}, 'NativeIOFileSync.close is idempotent');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, 'file_name');
assert_equals(undefined, file.close());

Expand All @@ -36,6 +24,8 @@ test(testCase => {
}, 'NativeIOFileSync.read fails after NativeIOFileSync.close');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, 'file_name');
assert_equals(undefined, file.close());

Expand All @@ -44,20 +34,26 @@ test(testCase => {
}, 'NativeIOFile.write fails after NativeIOFile.close');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, 'file_name');
assert_equals(undefined, file.close());

assert_throws_dom('InvalidStateError', () => file.getLength());
}, 'NativeIOFileSync.getLength fails after NativeIOFileSync.close');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, 'file_name');
assert_equals(undefined, file.close());

assert_throws_dom('InvalidStateError', () => file.flush());
}, 'NativeIOFileSync.flush fails after NativeIOFileSync.close');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, 'file_name');
assert_equals(undefined, file.close());

Expand Down
21 changes: 7 additions & 14 deletions native-io/flush_sync_basic.tentative.https.any.js
Expand Up @@ -5,24 +5,17 @@
'use strict';

test(testCase => {
const file = storageFoundation.openSync('test_file');
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
});
reserveAndCleanupCapacitySync(testCase);

const size = 1024;
const longarray = createLargeArray(size, /*seed = */ 107);
const writtenBytes = Uint8Array.from(longarray);
const writeCount = file.write(writtenBytes, 0);
assert_equals(
writeCount, size,
'NativeIOFile.write() should resolve with the number of bytes written');
const longArray = createLargeArray(size, /*seed = */ 107);

const file = createFileSync(testCase, 'test_file', longArray);

file.flush();
const readBytes = readIoFileSync(file);

assert_array_equals(readBytes, writtenBytes,
'the bytes read should match the bytes written');
assert_array_equals(readBytes, longArray,
'the bytes read should match the bytes written');
}, 'NativeIOFileSync.read returns bytes written by NativeIOFileSync.write' +
' after NativeIOFileSync.flush');
' after NativeIOFileSync.flush');
34 changes: 12 additions & 22 deletions native-io/getLength_setLength_sync_basic.tentative.https.any.js
Expand Up @@ -5,44 +5,34 @@
'use strict';

test(testCase => {
const file = storageFoundation.openSync('test_file');
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
});
reserveAndCleanupCapacitySync(testCase);

const writtenBytes = Uint8Array.from([97, 98, 99, 100]);
file.write(writtenBytes, 0);
const file = createFileSync(testCase, 'test_file', [97, 98, 99, 100]);

file.setLength(3);
const readBytes = readIoFileSync(file);

const remainingBytes = Uint8Array.from([97, 98, 99]);
assert_array_equals(
readBytes, remainingBytes,
'NativeIOFileSync.setLength() should remove bytes from the end of ' +
'a file when decreasing its length.');
readBytes, remainingBytes,
'NativeIOFileSync.setLength() should remove bytes from the end of ' +
'a file when decreasing its length.');
}, 'NativeIOFileSync.setLength shrinks a file and' +
' NativeIOFileSync.getLength reports its new length.');
' NativeIOFileSync.getLength reports its new length.');

test(testCase => {
const file = storageFoundation.openSync('test_file');
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
});
reserveAndCleanupCapacitySync(testCase);

const writtenBytes = Uint8Array.from([97, 98, 99, 100]);
file.write(writtenBytes, 0);
const file = createFileSync(testCase, 'test_file', [97, 98, 99, 100]);

file.setLength(5);
const readBytes = readIoFileSync(file);

const expectedBytes = Uint8Array.from([97, 98, 99, 100, 0]);

assert_array_equals(
readBytes, expectedBytes,
'NativeIOFileSync.setLength() should append zeros when increasing' +
' the file size.');
readBytes, expectedBytes,
'NativeIOFileSync.setLength() should append zeros when increasing' +
' the file size.');
}, 'NativeIOFileSync.setLength appends zeros to a file and ' +
'NativeIOFileSync.getLength reports its new length.');
'NativeIOFileSync.getLength reports its new length.');
4 changes: 4 additions & 0 deletions native-io/read_write_sync_basic.tentative.https.any.js
@@ -1,9 +1,13 @@
// META: title=Synchronous NativeIO API: Written bytes are read back.
// META: global=dedicatedworker
// META: script=resources/support.js

'use strict';


test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = storageFoundation.openSync('test_file');
testCase.add_cleanup(() => {
file.close();
Expand Down
12 changes: 12 additions & 0 deletions native-io/rename_sync_failure_handling.tentative.https.any.js
Expand Up @@ -12,6 +12,8 @@ setup(() => {
});

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file1 = storageFoundation.openSync('test_file_1');
const file2 = storageFoundation.openSync('test_file_2');
testCase.add_cleanup(() => {
Expand Down Expand Up @@ -58,6 +60,8 @@ test(testCase => {
}, 'storageFoundation.renameSync does not overwrite an existing file.');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = storageFoundation.openSync('test_file');
testCase.add_cleanup(() => {
file.close();
Expand All @@ -74,6 +78,8 @@ test(testCase => {
}, 'storageFoundation.renameSync allows renaming an open file.');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
Expand All @@ -94,6 +100,8 @@ test(testCase => {
' names.');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const closed_file = storageFoundation.openSync('closed_file');
closed_file.close();
const opened_file = storageFoundation.openSync('opened_file');
Expand All @@ -115,6 +123,8 @@ test(testCase => {
}, 'Failed storageFoundation.renameSync does not unlock the source.');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const closed_file = storageFoundation.openSync('closed_file');
closed_file.close();
const opened_file = storageFoundation.openSync('opened_file');
Expand All @@ -136,6 +146,8 @@ test(testCase => {
}, 'Failed storageFoundation.renameSync does not unlock the destination.');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

// Make sure that the file does not exist.
storageFoundation.deleteSync('does_not_exist');
testCase.add_cleanup(() => {
Expand Down
17 changes: 14 additions & 3 deletions native-io/resources/support.js
Expand Up @@ -33,16 +33,17 @@ async function createFile(testCase, fileName, data = [64, 65, 66, 67]) {
// Returns a handle to a newly created file that holds some data.
//
// The file will be closed and deleted when the test ends.
function createFileSync(testCase, fileName) {
function createFileSync(testCase, fileName, data = [64, 65, 66, 67]) {
const file = storageFoundation.openSync(fileName);
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync(fileName);
});

const writtenBytes = Uint8Array.from([64, 65, 66, 67]);
const writtenBytes = Uint8Array.from(data);
const writeCount = file.write(writtenBytes, 0);
assert_equals(writeCount, 4);
assert_equals(writeCount, data.length,
'NativeIOFileSync.write() should resolve with the number of bytes written');

return file;
}
Expand Down Expand Up @@ -93,3 +94,13 @@ async function reserveAndCleanupCapacity(testCase,
});
assert_greater_than_equal(grantedCapacity, capacity);
}

// Default capacity allocation for non-quota related sync tests.
function reserveAndCleanupCapacitySync(testCase, capacity = kDefaultCapacity) {
const grantedCapacity = storageFoundation.requestCapacitySync(capacity);
testCase.add_cleanup(() => {
let available_capacity = storageFoundation.getRemainingCapacitySync();
storageFoundation.releaseCapacitySync(available_capacity);
});
assert_greater_than_equal(grantedCapacity, capacity);
}
4 changes: 4 additions & 0 deletions native-io/setLength_bounds_sync.tentative.https.any.js
Expand Up @@ -5,6 +5,8 @@
'use strict';

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, "file_length_zero");
file.setLength(0);
const lengthDecreased = file.getLength();
Expand All @@ -14,6 +16,8 @@ test(testCase => {
'the file length to 0.');

test(testCase => {
reserveAndCleanupCapacitySync(testCase);

const file = createFileSync(testCase, "file_length_negative");

// Without this assertion, the test passes even if setLength is not defined.
Expand Down
@@ -0,0 +1,53 @@
// META: title=NativeIO API: SetLength respects the allocated capacities.
// META: global=dedicatedworker

test(testCase => {
const file = storageFoundation.openSync('test_file');
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
});
assert_throws_dom('QuotaExceededError', () => {file.setLength(4)});
}, 'setLength() fails without any capacity request.');

test(testCase => {
const file = storageFoundation.openSync('test_file');

const granted_capacity = storageFoundation.requestCapacitySync(4);
assert_greater_than_equal(granted_capacity, 2);
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
storageFoundation.releaseCapacitySync(1);
});

file.setLength(granted_capacity - 1);
}, 'setLength() succeeds when given the granted capacity - 1');

test(testCase => {
const file = storageFoundation.openSync('test_file');

const granted_capacity = storageFoundation.requestCapacitySync(4);
assert_greater_than_equal(granted_capacity, 1);
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
});

file.setLength(granted_capacity);
}, 'setLength() succeeds when given the granted capacity');

test(testCase => {
const file = storageFoundation.openSync('test_file');

const granted_capacity = storageFoundation.requestCapacitySync(4);
assert_greater_than_equal(granted_capacity, 0);
testCase.add_cleanup(() => {
file.close();
storageFoundation.deleteSync('test_file');
storageFoundation.releaseCapacitySync(granted_capacity);
});

assert_throws_dom('QuotaExceededError',
() => {file.setLength(granted_capacity + 1)});
}, 'setLength() fails when given the granted capacity + 1');

0 comments on commit 4448bdc

Please sign in to comment.