Bug 1471025: Part 2 - Add a helper class creating and accessing shared preference map snapshots. r=njn,erahm

This is based on the SharedStringMap that's currently used for shared memory
string bundles.

When the parent process is ready to launch its first content process, it
creates a snapshot of the current state of the preference database, maps that
as read-only, and shares it with each content process. Look-ups in the
snapshotted map are done entirely using data in the shared memory region. It
doesn't require any additional per-process state data.

MozReview-Commit-ID: BdTUhak7dmS
This commit is contained in:
Kris Maglione
2018-07-01 18:28:31 -07:00
parent 9215d401a6
commit d6fbdc0147
10 changed files with 1363 additions and 100 deletions

View File

@@ -8,6 +8,8 @@
#include <stdlib.h>
#include <string.h>
#include "SharedPrefMap.h"
#include "base/basictypes.h"
#include "GeckoProfiler.h"
#include "MainThreadUtils.h"
@@ -93,6 +95,8 @@
using namespace mozilla;
using mozilla::ipc::FileDescriptor;
#ifdef DEBUG
#define ENSURE_PARENT_PROCESS(func, pref) \
@@ -127,15 +131,6 @@ static const uint32_t MAX_PREF_LENGTH = 1 * 1024 * 1024;
// Actually, 4kb should be enough for everyone.
static const uint32_t MAX_ADVISABLE_PREF_LENGTH = 4 * 1024;
// Keep this in sync with PrefType in parser/src/lib.rs.
enum class PrefType : uint8_t
{
None = 0, // only used when neither the default nor user value is set
String = 1,
Int = 2,
Bool = 3,
};
// This is used for pref names and string pref values. We encode the string
// length, then a '/', then the string chars. This encoding means there are no
// special chars that are forbidden or require escaping.
@@ -189,6 +184,9 @@ union PrefValue {
}
}
template<typename T>
T Get() const;
void Init(PrefType aNewType, PrefValue aNewValue)
{
if (aNewType == PrefType::String) {
@@ -318,6 +316,27 @@ union PrefValue {
}
};
template<>
bool
PrefValue::Get() const
{
return mBoolVal;
}
template<>
int32_t
PrefValue::Get() const
{
return mIntVal;
}
template<>
nsDependentCString
PrefValue::Get() const
{
return nsDependentCString(mStringVal);
}
#ifdef DEBUG
const char*
PrefTypeToString(PrefType aType)
@@ -468,6 +487,29 @@ public:
bool HasDefaultValue() const { return mHasDefaultValue; }
bool HasUserValue() const { return mHasUserValue; }
template<typename T>
void AddToMap(SharedPrefMapBuilder& aMap)
{
aMap.Add(
Name(),
{ HasDefaultValue(), HasUserValue(), uint8_t(mIsSticky), IsLocked() },
HasDefaultValue() ? mDefaultValue.Get<T>() : T(),
HasUserValue() ? mUserValue.Get<T>() : T());
}
void AddToMap(SharedPrefMapBuilder& aMap)
{
if (IsTypeBool()) {
AddToMap<bool>(aMap);
} else if (IsTypeInt()) {
AddToMap<int32_t>(aMap);
} else if (IsTypeString()) {
AddToMap<nsDependentCString>(aMap);
} else {
MOZ_ASSERT_UNREACHABLE("Unexpected preference type");
}
}
// When a content process is created we could tell it about every pref. But
// the content process also initializes prefs from file, so we save a lot of
// IPC if we only tell it about prefs that have changed since initialization.
@@ -1064,6 +1106,8 @@ private:
static PLDHashTable* gHashTable;
static StaticRefPtr<SharedPrefMap> gSharedMap;
// The callback list contains all the priority callbacks followed by the
// non-priority callbacks. gLastPriorityNode records where the first part ends.
static CallbackNode* gFirstCallback = nullptr;
@@ -3018,6 +3062,10 @@ PreferenceServiceReporter::CollectReports(
node->AddSizeOfIncludingThis(mallocSizeOf, sizes);
}
if (gSharedMap) {
sizes.mMisc += mallocSizeOf(gSharedMap);
}
MOZ_COLLECT_REPORT("explicit/preferences/hash-table",
KIND_HEAP,
UNITS_BYTES,
@@ -3073,6 +3121,17 @@ PreferenceServiceReporter::CollectReports(
sizes.mMisc,
"Miscellaneous memory used by libpref.");
if (gSharedMap) {
if (XRE_IsParentProcess()) {
MOZ_COLLECT_REPORT("explicit/preferences/shared-memory-map",
KIND_NONHEAP,
UNITS_BYTES,
gSharedMap->MapSize(),
"The shared memory mapping used to share a "
"snapshot of preference values across processes.");
}
}
nsPrefBranch* rootBranch =
static_cast<nsPrefBranch*>(Preferences::GetRootBranch());
if (!rootBranch) {
@@ -3445,6 +3504,8 @@ Preferences::~Preferences()
delete gAccessCounts;
#endif
gSharedMap = nullptr;
gPrefNameArena.Clear();
}
@@ -3496,6 +3557,36 @@ Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen)
#endif
}
/* static */ FileDescriptor
Preferences::EnsureSnapshot(size_t* aSize)
{
MOZ_ASSERT(XRE_IsParentProcess());
if (!gSharedMap) {
SharedPrefMapBuilder builder;
for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
Pref* pref = static_cast<PrefEntry*>(iter.Get())->mPref;
pref->AddToMap(builder);
}
gSharedMap = new SharedPrefMap(std::move(builder));
}
*aSize = gSharedMap->MapSize();
return gSharedMap->CloneFileDescriptor();
}
/* static */ void
Preferences::InitSnapshot(const FileDescriptor& aHandle, size_t aSize)
{
MOZ_ASSERT(!XRE_IsParentProcess());
MOZ_ASSERT(!gSharedMap);
gSharedMap = new SharedPrefMap(aHandle, aSize);
}
/* static */ void
Preferences::InitializeUserPrefs()
{