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:
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user