Bug 1463587: Part 6 - Add an idle flush task to WritableSharedMap. r=erahm

MozReview-Commit-ID: 8Ht7zHo4PD6

--HG--
extra : rebase_source : daaaec86b027d329296e86d508b52342aca64bc0
This commit is contained in:
Kris Maglione 2018-06-27 16:44:22 -07:00
Родитель bb78a2116c
Коммит f16c7a4e5d
3 изменённых файлов: 61 добавлений и 13 удалений

Просмотреть файл

@ -460,12 +460,28 @@ WritableSharedMap::Flush()
}
void
WritableSharedMap::IdleFlush()
{
mPendingFlush = false;
Flush();
}
nsresult
WritableSharedMap::KeyChanged(const nsACString& aName)
{
if (!mChangedKeys.ContainsSorted(aName)) {
mChangedKeys.InsertElementSorted(aName);
}
mEntryArray.reset();
if (!mPendingFlush) {
MOZ_TRY(NS_IdleDispatchToCurrentThread(
NewRunnableMethod("WritableSharedMap::IdleFlush",
this,
&WritableSharedMap::IdleFlush)));
mPendingFlush = true;
}
return NS_OK;
}

Просмотреть файл

@ -38,9 +38,11 @@ namespace ipc {
* they are updated, and lazily decoded each time they're read.
*
* Updates are batched. Rather than each key change triggering an immediate
* update, combined updates are broadcast after a delay. Currently, this
* requires an explicit flush() call, or spawning a new content process. In the
* future, it will happen automatically in idle tasks.
* update, combined updates are broadcast after a delay. Changes are flushed
* immediately any time a new process is created. Additionally, any time a key
* is changed, a flush task is scheduled for the next time the event loop
* becomes idle. Changes can be flushed immediately by calling the flush()
* method.
*
*
* Whenever a read-only SharedMap is updated, it dispatches a "change" event.
@ -366,18 +368,22 @@ private:
RefPtr<SharedMap> mReadOnly;
bool mPendingFlush = false;
// Creates a new snapshot of the map, and updates all Entry instance to
// reference its data.
Result<Ok, nsresult> Serialize();
void IdleFlush();
// If there have been any changes since the last snapshot, creates a new
// serialization and broadcasts it to all child SharedMap instances.
void BroadcastChanges();
// Marks the given (UTF-8 encoded) key as having changed. This adds it to
// mChangedKeys, if not already present. In the future, it will also schedule
// a flush the next time the event loop is idle.
void KeyChanged(const nsACString& aName);
// mChangedKeys, if not already present, and schedules a flush for the next
// time the event loop is idle.
nsresult KeyChanged(const nsACString& aName);
};
} // ipc

Просмотреть файл

@ -46,13 +46,15 @@ function checkParentMap(expected) {
checkMap(getContents(Services.ppmm.sharedData), expected);
}
async function checkContentMaps(expected) {
async function checkContentMaps(expected, parentOnly = false) {
info("Checking in-process content map");
checkMap(getContents(Services.cpmm.sharedData), expected);
info("Checking out-of-process content map");
let contents = await contentPage.spawn(undefined, getContents);
checkMap(contents, expected);
if (!parentOnly) {
info("Checking out-of-process content map");
let contents = await contentPage.spawn(undefined, getContents);
checkMap(contents, expected);
}
}
add_task(async function setup() {
@ -108,22 +110,26 @@ add_task(async function test_sharedMap() {
setKey("baz-a", {meh: "meh"});
// When we do several checks in a row, we can't check the values in
// the content process, since the async checks may allow the idle
// flush task to run, and update it before we're ready.
checkParentMap(expected);
await checkContentMaps(oldExpected);
checkContentMaps(oldExpected, true);
info("Add another entry. Check that both new entries are only available in the parent");
setKey("baz-a", {meh: 12});
checkParentMap(expected);
await checkContentMaps(oldExpected);
checkContentMaps(oldExpected, true);
info("Delete an entry. Check that all changes are only visible in the parent");
deleteKey("foo-b");
checkParentMap(expected);
await checkContentMaps(oldExpected);
checkContentMaps(oldExpected, true);
info("Flush. Check that all entries are available in both parent and children");
@ -131,4 +137,24 @@ add_task(async function test_sharedMap() {
checkParentMap(expected);
await checkContentMaps(expected);
info("Test that entries are automatically flushed on idle:");
info("Add a new entry. Check that it is initially only available in the parent");
// Test the idle flush task.
oldExpected = Array.from(expected);
setKey("thing", "stuff");
checkParentMap(expected);
checkContentMaps(oldExpected, true);
info("Wait for an idle timeout. Check that changes are now visible in all children");
await new Promise(resolve => ChromeUtils.idleDispatch(resolve));
checkParentMap(expected);
await checkContentMaps(expected);
});