mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 520309, startupcache core r=dwitte sr=bsmedberg a=bsmedberg
This commit is contained in:
parent
976a5d3c42
commit
fba716bbcd
@ -736,6 +736,12 @@ PRUint8* nsZipArchive::GetData(nsZipItem* aItem)
|
||||
return data + offset;
|
||||
}
|
||||
|
||||
PRBool
|
||||
nsZipArchive::CheckCRC(nsZipItem* aItem, PRUint8* aItemData) {
|
||||
PRUint32 crc = crc32(0, (const unsigned char*)aItemData, aItem->Size());
|
||||
return crc == aItem->CRC32();
|
||||
}
|
||||
|
||||
//------------------------------------------
|
||||
// nsZipArchive constructor and destructor
|
||||
//------------------------------------------
|
||||
|
@ -196,6 +196,8 @@ public:
|
||||
*/
|
||||
PRUint8* GetData(nsZipItem* aItem);
|
||||
|
||||
PRBool CheckCRC(nsZipItem* aItem, PRUint8* aData);
|
||||
|
||||
private:
|
||||
//--- private members ---
|
||||
|
||||
|
82
startupcache/Makefile.in
Normal file
82
startupcache/Makefile.in
Normal file
@ -0,0 +1,82 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is Startup Cache.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Benedict Hsieh <bhsieh@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
|
||||
DEPTH = ..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = $(NULL)
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
TOOL_DIRS += test
|
||||
endif
|
||||
|
||||
MODULE = startupcache
|
||||
MODULE_NAME = StartupCacheModule
|
||||
LIBRARY_NAME = startupcache
|
||||
SHORT_LIBNAME = scache
|
||||
EXPORT_LIBRARY = 1
|
||||
LIBXUL_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
GRE_MODULE = 1
|
||||
|
||||
CPPSRCS = StartupCache.cpp \
|
||||
StartupCacheUtils.cpp \
|
||||
StartupCacheModule.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES = mozilla/scache
|
||||
EXPORTS_mozilla/scache = StartupCache.h \
|
||||
StartupCacheUtils.h \
|
||||
$(NULL)
|
||||
|
||||
XPIDLSRCS = nsIStartupCache.idl \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS += \
|
||||
$(LIBS_DIR) \
|
||||
$(ZLIB_LIBS) \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
628
startupcache/StartupCache.cpp
Normal file
628
startupcache/StartupCache.cpp
Normal file
@ -0,0 +1,628 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Startup Cache.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "prio.h"
|
||||
#include "prtypes.h"
|
||||
#include "pldhash.h"
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIStartupCache.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsIStreamBufferAccess.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIZipWriter.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsZipArchive.h"
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
#define SC_ENDIAN "big"
|
||||
#else
|
||||
#define SC_ENDIAN "little"
|
||||
#endif
|
||||
|
||||
#if PR_BYTES_PER_WORD == 4
|
||||
#define SC_WORDSIZE "4"
|
||||
#else
|
||||
#define SC_WORDSIZE "8"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace scache {
|
||||
|
||||
static const char sStartupCacheName[] = "startupCache." SC_WORDSIZE "." SC_ENDIAN;
|
||||
static NS_DEFINE_CID(kZipReaderCID, NS_ZIPREADER_CID);
|
||||
|
||||
StartupCache*
|
||||
StartupCache::GetSingleton()
|
||||
{
|
||||
if (!gStartupCache)
|
||||
StartupCache::InitSingleton();
|
||||
|
||||
return StartupCache::gStartupCache;
|
||||
}
|
||||
|
||||
void
|
||||
StartupCache::DeleteSingleton()
|
||||
{
|
||||
delete StartupCache::gStartupCache;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCache::InitSingleton()
|
||||
{
|
||||
nsresult rv;
|
||||
StartupCache::gStartupCache = new StartupCache();
|
||||
|
||||
rv = StartupCache::gStartupCache->Init();
|
||||
if (NS_FAILED(rv)) {
|
||||
delete StartupCache::gStartupCache;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
StartupCache* StartupCache::gStartupCache;
|
||||
PRBool StartupCache::gShutdownInitiated;
|
||||
|
||||
StartupCache::StartupCache()
|
||||
: mArchive(NULL), mStartupWriteInitiated(PR_FALSE) { }
|
||||
|
||||
StartupCache::~StartupCache()
|
||||
{
|
||||
// Generally, the in-memory table should be empty here,
|
||||
// but in special cases (like Talos Ts tests) we
|
||||
// could shut down before we write.
|
||||
// This mechanism will change when IO is moved off-thread
|
||||
// (bug 586859) or when Talos first-run is changed to allow
|
||||
// our timer to work (bug 591471).
|
||||
WriteToDisk();
|
||||
gStartupCache = nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCache::Init()
|
||||
{
|
||||
nsresult rv;
|
||||
mTable.Init();
|
||||
#ifdef DEBUG
|
||||
mWriteObjectMap.Init();
|
||||
#endif
|
||||
|
||||
mZipW = do_CreateInstance("@mozilla.org/zipwriter;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIFile> file;
|
||||
rv = NS_GetSpecialDirectory("ProfLDS",
|
||||
getter_AddRefs(file));
|
||||
if (NS_FAILED(rv)) {
|
||||
// return silently, this will fail in mochitests's xpcshell process.
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING("startupCache"));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Try to create the directory if it's not there yet
|
||||
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)
|
||||
return rv;
|
||||
|
||||
rv = file->AppendNative(NS_LITERAL_CSTRING(sStartupCacheName));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mFile = do_QueryInterface(file);
|
||||
NS_ENSURE_TRUE(mFile, NS_ERROR_UNEXPECTED);
|
||||
|
||||
mObserverService = do_GetService("@mozilla.org/observer-service;1");
|
||||
|
||||
if (!mObserverService) {
|
||||
NS_WARNING("Could not get observerService.");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
mListener = new StartupCacheListener();
|
||||
rv = mObserverService->AddObserver(mListener, NS_XPCOM_SHUTDOWN_OBSERVER_ID,
|
||||
PR_FALSE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = LoadArchive();
|
||||
|
||||
// Sometimes we don't have a cache yet, that's ok.
|
||||
// If it's corrupted, just remove it and start over.
|
||||
if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND) {
|
||||
NS_WARNING("Failed to load startupcache file correctly, removing!");
|
||||
InvalidateCache();
|
||||
}
|
||||
|
||||
mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// Wait for 10 seconds, then write out the cache.
|
||||
rv = mTimer->InitWithFuncCallback(StartupCache::WriteTimeout, this, 10000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCache::LoadArchive()
|
||||
{
|
||||
PRBool exists;
|
||||
mArchive = NULL;
|
||||
nsresult rv = mFile->Exists(&exists);
|
||||
if (NS_FAILED(rv) || !exists)
|
||||
return NS_ERROR_FILE_NOT_FOUND;
|
||||
|
||||
mArchive = new nsZipArchive();
|
||||
return mArchive->OpenArchive(mFile);
|
||||
}
|
||||
|
||||
// NOTE: this will not find a new entry until it has been written to disk!
|
||||
// Consumer should take ownership of the resulting buffer.
|
||||
nsresult
|
||||
StartupCache::GetBuffer(const char* id, char** outbuf, PRUint32* length)
|
||||
{
|
||||
PRBool exists;
|
||||
char* data = NULL;
|
||||
PRUint32 len;
|
||||
|
||||
if (!mStartupWriteInitiated) {
|
||||
CacheEntry* entry;
|
||||
nsDependentCString idStr(id);
|
||||
mTable.Get(idStr, &entry);
|
||||
if (entry) {
|
||||
data = entry->data;
|
||||
len = entry->size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data && mArchive) {
|
||||
nsZipItem* zipItem = mArchive->GetItem(id);
|
||||
if (zipItem) {
|
||||
PRUint8* itemData = mArchive->GetData(zipItem);
|
||||
if (!itemData || !mArchive->CheckCRC(zipItem, itemData)) {
|
||||
NS_WARNING("StartupCache file corrupted!");
|
||||
InvalidateCache();
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
len = zipItem->Size();
|
||||
data = (char*) itemData;
|
||||
}
|
||||
}
|
||||
|
||||
if (data) {
|
||||
*outbuf = new char[len];
|
||||
memcpy(*outbuf, data, len);
|
||||
*length = len;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Makes a copy of the buffer, client retains ownership of inbuf.
|
||||
nsresult
|
||||
StartupCache::PutBuffer(const char* id, const char* inbuf, PRUint32 len)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (StartupCache::gShutdownInitiated) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsAutoArrayPtr<char> data(new char[len]);
|
||||
memcpy(data, inbuf, len);
|
||||
|
||||
nsDependentCString idStr(id);
|
||||
if (!mStartupWriteInitiated) {
|
||||
// Cache it for now, we'll write all together later.
|
||||
CacheEntry* entry;
|
||||
|
||||
#ifdef DEBUG
|
||||
mTable.Get(idStr, &entry);
|
||||
NS_ASSERTION(entry == nsnull, "Existing entry in StartupCache.");
|
||||
|
||||
if (mArchive) {
|
||||
nsZipItem* zipItem = mArchive->GetItem(id);
|
||||
NS_ASSERTION(zipItem == nsnull, "Existing entry in disk StartupCache.");
|
||||
}
|
||||
#endif
|
||||
|
||||
entry = new CacheEntry(data.forget(), len);
|
||||
mTable.Put(idStr, entry);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
rv = mZipW->Open(mFile, PR_RDWR | PR_CREATE_FILE);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// XXX We need to think about whether to write this out every time,
|
||||
// or somehow detect a good time to write. We need to finish writing
|
||||
// before shutdown though, and writing also requires a reload of the
|
||||
// reader's archive, which probably can't handle having the underlying
|
||||
// file change underneath it. Potentially could reload on the next
|
||||
// read request, if this is a problem. See Bug 586859.
|
||||
#ifdef DEBUG
|
||||
PRBool hasEntry;
|
||||
rv = mZipW->HasEntry(idStr, &hasEntry);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ASSERTION(hasEntry == PR_FALSE, "Existing entry in disk StartupCache.");
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIStringInputStream> stream
|
||||
= do_CreateInstance("@mozilla.org/io/string-input-stream;1",
|
||||
&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = stream->AdoptData(data, len);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
data.forget();
|
||||
|
||||
rv = mZipW->AddEntryStream(idStr, 0, 0, stream, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Close the archive so Windows doesn't choke.
|
||||
mArchive = NULL;
|
||||
rv = mZipW->Close();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// our reader's view of the archive is outdated now, reload it.
|
||||
return LoadArchive();
|
||||
}
|
||||
|
||||
struct CacheWriteHolder
|
||||
{
|
||||
nsCOMPtr<nsIZipWriter> writer;
|
||||
nsCOMPtr<nsIStringInputStream> stream;
|
||||
};
|
||||
|
||||
PLDHashOperator
|
||||
CacheCloseHelper(const nsACString& key, nsAutoPtr<CacheEntry>& data,
|
||||
void* closure)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
CacheWriteHolder* holder = (CacheWriteHolder*) closure;
|
||||
nsIStringInputStream* stream = holder->stream;
|
||||
nsIZipWriter* writer = holder->writer;
|
||||
|
||||
stream->ShareData(data->data, data->size);
|
||||
|
||||
#ifdef DEBUG
|
||||
PRBool hasEntry;
|
||||
rv = writer->HasEntry(key, &hasEntry);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && hasEntry == PR_FALSE,
|
||||
"Existing entry in disk StartupCache.");
|
||||
#endif
|
||||
rv = writer->AddEntryStream(key, 0, 0, stream, false);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("cache entry deleted but not written to disk.");
|
||||
}
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
StartupCache::WriteToDisk()
|
||||
{
|
||||
nsresult rv;
|
||||
mStartupWriteInitiated = PR_TRUE;
|
||||
|
||||
if (mTable.Count() == 0)
|
||||
return;
|
||||
|
||||
rv = mZipW->Open(mFile, PR_RDWR | PR_CREATE_FILE);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("could not open zipfile for write");
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStringInputStream> stream
|
||||
= do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Couldn't create string input stream.");
|
||||
return;
|
||||
}
|
||||
|
||||
CacheWriteHolder holder;
|
||||
holder.stream = stream;
|
||||
holder.writer = mZipW;
|
||||
|
||||
mTable.Enumerate(CacheCloseHelper, &holder);
|
||||
|
||||
// Close the archive so Windows doesn't choke.
|
||||
mArchive = NULL;
|
||||
mZipW->Close();
|
||||
|
||||
// our reader's view of the archive is outdated now, reload it.
|
||||
LoadArchive();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
StartupCache::InvalidateCache()
|
||||
{
|
||||
mTable.Clear();
|
||||
mArchive = NULL;
|
||||
|
||||
// This is usually closed, but it's possible to get into
|
||||
// an inconsistent state.
|
||||
mZipW->Close();
|
||||
mFile->Remove(false);
|
||||
LoadArchive();
|
||||
}
|
||||
|
||||
void
|
||||
StartupCache::WriteTimeout(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
StartupCache* sc = (StartupCache*) aClosure;
|
||||
sc->WriteToDisk();
|
||||
}
|
||||
|
||||
// We don't want to refcount StartupCache, so we'll just
|
||||
// hold a ref to this and pass it to observerService instead.
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(StartupCacheListener, nsIObserver)
|
||||
|
||||
nsresult
|
||||
StartupCacheListener::Observe(nsISupports *subject, const char* topic, const PRUnichar* data)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
if (strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
|
||||
StartupCache::gShutdownInitiated = PR_TRUE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCache::GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
|
||||
nsIObjectOutputStream** aOutStream)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aStream);
|
||||
#ifdef DEBUG
|
||||
StartupCacheDebugOutputStream* stream
|
||||
= new StartupCacheDebugOutputStream(aStream, &mWriteObjectMap);
|
||||
NS_ADDREF(*aOutStream = stream);
|
||||
#else
|
||||
NS_ADDREF(*aOutStream = aStream);
|
||||
#endif
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// StartupCacheDebugOutputStream implementation
|
||||
#ifdef DEBUG
|
||||
NS_IMPL_ISUPPORTS3(StartupCacheDebugOutputStream, nsIObjectOutputStream,
|
||||
nsIBinaryOutputStream, nsIOutputStream)
|
||||
|
||||
PRBool
|
||||
StartupCacheDebugOutputStream::CheckReferences(nsISupports* aObject)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aObject);
|
||||
if (!classInfo) {
|
||||
NS_ERROR("aObject must implement nsIClassInfo");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
PRUint32 flags;
|
||||
rv = classInfo->GetFlags(&flags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (flags & nsIClassInfo::SINGLETON)
|
||||
return PR_TRUE;
|
||||
|
||||
nsISupportsHashKey* key = mObjectMap->GetEntry(aObject);
|
||||
if (key) {
|
||||
NS_ERROR("non-singleton aObject is referenced multiple times in this"
|
||||
"serialization, we don't support that.");
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
mObjectMap->PutEntry(aObject);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// nsIObjectOutputStream implementation
|
||||
nsresult
|
||||
StartupCacheDebugOutputStream::WriteObject(nsISupports* aObject, PRBool aIsStrongRef)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
|
||||
|
||||
NS_ASSERTION(rootObject.get() == aObject,
|
||||
"bad call to WriteObject -- call WriteCompoundObject!");
|
||||
PRBool check = CheckReferences(aObject);
|
||||
NS_ENSURE_TRUE(check, NS_ERROR_FAILURE);
|
||||
return mBinaryStream->WriteObject(aObject, aIsStrongRef);
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheDebugOutputStream::WriteSingleRefObject(nsISupports* aObject)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
|
||||
|
||||
NS_ASSERTION(rootObject.get() == aObject,
|
||||
"bad call to WriteSingleRefObject -- call WriteCompoundObject!");
|
||||
PRBool check = CheckReferences(aObject);
|
||||
NS_ENSURE_TRUE(check, NS_ERROR_FAILURE);
|
||||
return mBinaryStream->WriteSingleRefObject(aObject);
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheDebugOutputStream::WriteCompoundObject(nsISupports* aObject,
|
||||
const nsIID& aIID,
|
||||
PRBool aIsStrongRef)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsISupports> rootObject(do_QueryInterface(aObject));
|
||||
|
||||
nsCOMPtr<nsISupports> roundtrip;
|
||||
rootObject->QueryInterface(aIID, getter_AddRefs(roundtrip));
|
||||
NS_ASSERTION(roundtrip.get() == aObject,
|
||||
"bad aggregation or multiple inheritance detected by call to "
|
||||
"WriteCompoundObject!");
|
||||
|
||||
PRBool check = CheckReferences(aObject);
|
||||
NS_ENSURE_TRUE(check, NS_ERROR_FAILURE);
|
||||
return mBinaryStream->WriteCompoundObject(aObject, aIID, aIsStrongRef);
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheDebugOutputStream::WriteID(nsID const& aID)
|
||||
{
|
||||
return mBinaryStream->WriteID(aID);
|
||||
}
|
||||
|
||||
char*
|
||||
StartupCacheDebugOutputStream::GetBuffer(PRUint32 aLength, PRUint32 aAlignMask)
|
||||
{
|
||||
return mBinaryStream->GetBuffer(aLength, aAlignMask);
|
||||
}
|
||||
|
||||
void
|
||||
StartupCacheDebugOutputStream::PutBuffer(char* aBuffer, PRUint32 aLength)
|
||||
{
|
||||
mBinaryStream->PutBuffer(aBuffer, aLength);
|
||||
}
|
||||
#endif //DEBUG
|
||||
|
||||
StartupCacheWrapper* StartupCacheWrapper::gStartupCacheWrapper = nsnull;
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(StartupCacheWrapper, nsIStartupCache)
|
||||
|
||||
StartupCacheWrapper* StartupCacheWrapper::GetSingleton()
|
||||
{
|
||||
if (!gStartupCacheWrapper)
|
||||
gStartupCacheWrapper = new StartupCacheWrapper();
|
||||
|
||||
NS_ADDREF(gStartupCacheWrapper);
|
||||
return gStartupCacheWrapper;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheWrapper::GetBuffer(const char* id, char** outbuf, PRUint32* length)
|
||||
{
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (!sc) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
return sc->GetBuffer(id, outbuf, length);
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheWrapper::PutBuffer(const char* id, char* inbuf, PRUint32 length)
|
||||
{
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (!sc) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
return sc->PutBuffer(id, inbuf, length);
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheWrapper::InvalidateCache()
|
||||
{
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (!sc) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
sc->InvalidateCache();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheWrapper::GetDebugObjectOutputStream(nsIObjectOutputStream* stream,
|
||||
nsIObjectOutputStream** outStream)
|
||||
{
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (!sc) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
return sc->GetDebugObjectOutputStream(stream, outStream);
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheWrapper::StartupWriteComplete(PRBool *complete)
|
||||
{
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (!sc) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
*complete = sc->mStartupWriteInitiated && sc->mTable.Count() == 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheWrapper::ResetStartupWriteTimer()
|
||||
{
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (!sc) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
sc->mStartupWriteInitiated = PR_FALSE;
|
||||
sc->mTimer->InitWithFuncCallback(StartupCache::WriteTimeout, sc, 10000,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
StartupCacheWrapper::GetObserver(nsIObserver** obv) {
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
if (!sc) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
NS_ADDREF(*obv = sc->mListener);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace scache
|
||||
} // namespace mozilla
|
223
startupcache/StartupCache.h
Normal file
223
startupcache/StartupCache.h
Normal file
@ -0,0 +1,223 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Startup Cache.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef StartupCache_h_
|
||||
#define StartupCache_h_
|
||||
|
||||
#include "prio.h"
|
||||
#include "prtypes.h"
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsIZipWriter.h"
|
||||
#include "nsIZipReader.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsZipArchive.h"
|
||||
#include "nsIStartupCache.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIFile.h"
|
||||
|
||||
/**
|
||||
* The StartupCache is a persistent cache of simple key-value pairs,
|
||||
* where the keys are null-terminated c-strings and the values are
|
||||
* arbitrary data, passed as a (char*, size) tuple.
|
||||
*
|
||||
* Clients should use the GetSingleton() static method to access the cache. It
|
||||
* will be available from the end of XPCOM init (NS_InitXPCOM3 in nsXPComInit.cpp),
|
||||
* until XPCOM shutdown begins. The GetSingleton() method will return null if the cache
|
||||
* is unavailable. The cache is only provided for libxul builds --
|
||||
* it will fail to link in non-libxul builds. The XPCOM interface is provided
|
||||
* only to allow compiled-code tests; clients should avoid using it.
|
||||
*
|
||||
* The API provided is very simple: GetBuffer() returns a buffer that was previously
|
||||
* stored in the cache (if any), and PutBuffer() inserts a buffer into the cache.
|
||||
* GetBuffer returns a new buffer, and the caller must take ownership of it.
|
||||
* PutBuffer will assert if the client attempts to insert a buffer with the same name as
|
||||
* an existing entry. The cache makes a copy of the passed-in buffer, so client
|
||||
* retains ownership.
|
||||
*
|
||||
* InvalidateCache() may be called if a client suspects data corruption
|
||||
* or wishes to invalidate for any other reason. This will remove all existing cache data.
|
||||
* Finally, getDebugObjectOutputStream() allows debug code to wrap an objectstream
|
||||
* with a debug objectstream, to check for multiply-referenced objects. These will
|
||||
* generally fail to deserialize correctly, unless they are stateless singletons or the
|
||||
* client maintains their own object data map for deserialization.
|
||||
*
|
||||
* Writes before the final-ui-startup notification are placed in an intermediate
|
||||
* cache in memory, then written out to disk at a later time, to get writes off the
|
||||
* startup path. In any case, clients should not rely on being able to GetBuffer()
|
||||
* data that is written to the cache, since it may not have been written to disk or
|
||||
* another client may have invalidated the cache. In other words, it should be used as
|
||||
* a cache only, and not a reliable persistent store.
|
||||
*
|
||||
* Some utility functions are provided in StartupCacheUtils. These functions wrap the
|
||||
* buffers into object streams, which may be useful for serializing objects. Note
|
||||
* the above caution about multiply-referenced objects, though -- the streams are just
|
||||
* as 'dumb' as the underlying buffers about multiply-referenced objects. They just
|
||||
* provide some convenience in writing out data.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
namespace scache {
|
||||
|
||||
struct CacheEntry
|
||||
{
|
||||
nsAutoArrayPtr<char> data;
|
||||
PRUint32 size;
|
||||
|
||||
CacheEntry() : data(nsnull), size(0) { }
|
||||
|
||||
// Takes possession of buf
|
||||
CacheEntry(char* buf, PRUint32 len) : data(buf), size(len) { }
|
||||
|
||||
~CacheEntry()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// We don't want to refcount StartupCache, and ObserverService wants to
|
||||
// refcount its listeners, so we'll let it refcount this instead.
|
||||
class StartupCacheListener : public nsIObserver
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
};
|
||||
|
||||
class StartupCache
|
||||
{
|
||||
|
||||
friend class StartupCacheListener;
|
||||
friend class StartupCacheWrapper;
|
||||
|
||||
public:
|
||||
|
||||
// StartupCache methods. See above comments for a more detailed description.
|
||||
|
||||
// Returns a buffer that was previously stored, caller takes ownership.
|
||||
nsresult GetBuffer(const char* id, char** outbuf, PRUint32* length);
|
||||
|
||||
// Stores a buffer. Caller keeps ownership, we make a copy.
|
||||
nsresult PutBuffer(const char* id, const char* inbuf, PRUint32 length);
|
||||
|
||||
// Removes the cache file.
|
||||
void InvalidateCache();
|
||||
|
||||
// In DEBUG builds, returns a stream that will attempt to check for
|
||||
// and disallow multiple writes of the same object.
|
||||
nsresult GetDebugObjectOutputStream(nsIObjectOutputStream* aStream,
|
||||
nsIObjectOutputStream** outStream);
|
||||
|
||||
static StartupCache* GetSingleton();
|
||||
static void DeleteSingleton();
|
||||
|
||||
private:
|
||||
StartupCache();
|
||||
~StartupCache();
|
||||
|
||||
nsresult LoadArchive();
|
||||
nsresult Init();
|
||||
void WriteToDisk();
|
||||
|
||||
static nsresult InitSingleton();
|
||||
static void WriteTimeout(nsITimer *aTimer, void *aClosure);
|
||||
|
||||
nsClassHashtable<nsCStringHashKey, CacheEntry> mTable;
|
||||
nsCOMPtr<nsIZipWriter> mZipW;
|
||||
nsAutoPtr<nsZipArchive> mArchive;
|
||||
nsCOMPtr<nsILocalFile> mFile;
|
||||
|
||||
nsCOMPtr<nsIObserverService> mObserverService;
|
||||
nsRefPtr<StartupCacheListener> mListener;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
||||
PRBool mStartupWriteInitiated;
|
||||
|
||||
static StartupCache *gStartupCache;
|
||||
static PRBool gShutdownInitiated;
|
||||
|
||||
#ifdef DEBUG
|
||||
nsTHashtable<nsISupportsHashKey> mWriteObjectMap;
|
||||
#endif
|
||||
};
|
||||
|
||||
// This debug outputstream attempts to detect if clients are writing multiple
|
||||
// references to the same object. We only support that if that object
|
||||
// is a singleton.
|
||||
#ifdef DEBUG
|
||||
class StartupCacheDebugOutputStream
|
||||
: public nsIObjectOutputStream
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBJECTOUTPUTSTREAM
|
||||
|
||||
StartupCacheDebugOutputStream (nsIObjectOutputStream* binaryStream,
|
||||
nsTHashtable<nsISupportsHashKey>* objectMap)
|
||||
: mBinaryStream(binaryStream), mObjectMap(objectMap) { }
|
||||
|
||||
NS_FORWARD_SAFE_NSIBINARYOUTPUTSTREAM(mBinaryStream)
|
||||
NS_FORWARD_SAFE_NSIOUTPUTSTREAM(mBinaryStream)
|
||||
|
||||
PRBool CheckReferences(nsISupports* aObject);
|
||||
|
||||
nsCOMPtr<nsIObjectOutputStream> mBinaryStream;
|
||||
nsTHashtable<nsISupportsHashKey> *mObjectMap;
|
||||
};
|
||||
#endif // DEBUG
|
||||
|
||||
// XPCOM wrapper interface provided for tests only.
|
||||
#define NS_STARTUPCACHE_CID \
|
||||
{0xae4505a9, 0x87ab, 0x477c, \
|
||||
{0xb5, 0x77, 0xf9, 0x23, 0x57, 0xed, 0xa8, 0x84}}
|
||||
// contract id: "@mozilla.org/startupcache/cache;1"
|
||||
|
||||
class StartupCacheWrapper
|
||||
: public nsIStartupCache
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTARTUPCACHE
|
||||
|
||||
static StartupCacheWrapper* GetSingleton();
|
||||
static StartupCacheWrapper *gStartupCacheWrapper;
|
||||
};
|
||||
|
||||
} // namespace scache
|
||||
} // namespace mozilla
|
||||
#endif //StartupCache_h_
|
83
startupcache/StartupCacheModule.cpp
Normal file
83
startupcache/StartupCacheModule.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Startup Cache.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "nscore.h"
|
||||
#include "pratom.h"
|
||||
#include "prmem.h"
|
||||
#include "prio.h"
|
||||
#include "plstr.h"
|
||||
#include "prlog.h"
|
||||
|
||||
#include "nsID.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIModule.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
|
||||
using namespace mozilla::scache;
|
||||
|
||||
// XXX Need help with guard for ENABLE_TEST
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(StartupCacheWrapper,
|
||||
StartupCacheWrapper::GetSingleton)
|
||||
NS_DEFINE_NAMED_CID(NS_STARTUPCACHE_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kStartupCacheCIDs[] = {
|
||||
{ &kNS_STARTUPCACHE_CID, false, NULL, StartupCacheWrapperConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kStartupCacheContracts[] = {
|
||||
{ "@mozilla.org/startupcache/cache;1", &kNS_STARTUPCACHE_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module kStartupCacheModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kStartupCacheCIDs,
|
||||
kStartupCacheContracts,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(StartupCacheModule) = &kStartupCacheModule;
|
90
startupcache/StartupCacheUtils.cpp
Normal file
90
startupcache/StartupCacheUtils.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "StartupCacheUtils.h"
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace scache {
|
||||
|
||||
NS_EXPORT nsresult
|
||||
NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
|
||||
nsIObjectInputStream** stream)
|
||||
{
|
||||
nsCOMPtr<nsIStringInputStream> stringStream
|
||||
= do_CreateInstance("@mozilla.org/io/string-input-stream;1");
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput
|
||||
= do_CreateInstance("@mozilla.org/binaryinputstream;1");
|
||||
|
||||
stringStream->AdoptData(buffer, len);
|
||||
objectInput->SetInputStream(stringStream);
|
||||
|
||||
objectInput.forget(stream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_EXPORT nsresult
|
||||
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
||||
nsIStorageStream** stream)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStorageStream> storageStream
|
||||
= do_CreateInstance("@mozilla.org/storagestream;1");
|
||||
|
||||
rv = storageStream->Init(256, PR_UINT32_MAX, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput
|
||||
= do_CreateInstance("@mozilla.org/binaryoutputstream;1");
|
||||
nsCOMPtr<nsIOutputStream> outputStream
|
||||
= do_QueryInterface(storageStream);
|
||||
|
||||
objectOutput->SetOutputStream(outputStream);
|
||||
|
||||
#ifdef DEBUG
|
||||
// Wrap in debug stream to detect unsupported writes of
|
||||
// multiply-referenced non-singleton objects
|
||||
StartupCache* sc = StartupCache::GetSingleton();
|
||||
NS_ENSURE_TRUE(sc, NS_ERROR_UNEXPECTED);
|
||||
nsCOMPtr<nsIObjectOutputStream> debugStream;
|
||||
sc->GetDebugObjectOutputStream(objectOutput, getter_AddRefs(debugStream));
|
||||
debugStream.forget(wrapperStream);
|
||||
#else
|
||||
objectOutput.forget(wrapperStream);
|
||||
#endif
|
||||
|
||||
storageStream.forget(stream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_EXPORT nsresult
|
||||
NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
|
||||
char** buffer, PRUint32* len)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 avail, read;
|
||||
rv = inputStream->Available(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoArrayPtr<char> temp (new char[avail]);
|
||||
rv = inputStream->Read(temp, avail, &read);
|
||||
if (NS_SUCCEEDED(rv) && avail != read)
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*len = avail;
|
||||
*buffer = temp.forget();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
63
startupcache/StartupCacheUtils.h
Normal file
63
startupcache/StartupCacheUtils.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Startup Cache.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
#ifndef nsStartupCacheUtils_h_
|
||||
#define nsStartupCacheUtils_h_
|
||||
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace scache {
|
||||
|
||||
NS_EXPORT nsresult
|
||||
NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
|
||||
nsIObjectInputStream** stream);
|
||||
|
||||
// We can't retrieve the wrapped stream from the objectOutputStream later,
|
||||
// so we return it here.
|
||||
NS_EXPORT nsresult
|
||||
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
||||
nsIStorageStream** stream);
|
||||
|
||||
NS_EXPORT nsresult
|
||||
NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
|
||||
char** buffer, PRUint32* len);
|
||||
}
|
||||
}
|
||||
#endif //nsStartupCacheUtils_h_
|
76
startupcache/nsIStartupCache.idl
Normal file
76
startupcache/nsIStartupCache.idl
Normal file
@ -0,0 +1,76 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Corporation startup cache code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIInputStream.idl"
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIObserver.idl"
|
||||
#include "nsIObjectOutputStream.idl"
|
||||
|
||||
[uuid(de798fab-af49-4a61-8144-81550986e1da)]
|
||||
interface nsIStartupCache : nsISupports
|
||||
{
|
||||
|
||||
/** This interface is provided for testing purposes only, basically
|
||||
* just to solve link vagaries. See docs in StartupCache.h
|
||||
* GetBuffer, PutBuffer, and InvalidateCache act as described
|
||||
* in that file. */
|
||||
|
||||
PRUint32 getBuffer(in string aID, out charPtr aBuffer);
|
||||
void putBuffer(in string aID, in charPtr aBuffer,
|
||||
in PRUint32 aLength);
|
||||
|
||||
void invalidateCache();
|
||||
|
||||
/** In debug builds, wraps this object output stream with a stream that will
|
||||
* detect and prevent the write of a multiply-referenced non-singleton object
|
||||
* during serialization. In non-debug, returns an add-ref'd pointer to
|
||||
* original stream, unwrapped. */
|
||||
nsIObjectOutputStream getDebugObjectOutputStream(in nsIObjectOutputStream aStream);
|
||||
|
||||
/* Allows clients to check whether the one-time writeout after startup
|
||||
* has finished yet, and also to set this variable as needed (so test
|
||||
* code can fire mulitple startup writes if needed).
|
||||
*/
|
||||
boolean startupWriteComplete();
|
||||
void resetStartupWriteTimer();
|
||||
|
||||
/* Allows clients to simulate the behavior of ObserverService. */
|
||||
readonly attribute nsIObserver observer;
|
||||
};
|
||||
|
124
startupcache/nsStartupCacheUtils.cpp
Normal file
124
startupcache/nsStartupCacheUtils.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Startup Cache.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsStartupCacheUtils.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
|
||||
nsresult
|
||||
NS_NewObjectInputStreamFromBuffer(char* buffer, int len,
|
||||
nsIObjectInputStream** stream)
|
||||
{
|
||||
nsCOMPtr<nsIStringInputStream> stringStream
|
||||
= do_CreateInstance("@mozilla.org/io/string-input-stream;1");
|
||||
if (!stringStream)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput
|
||||
= do_CreateInstance("@mozilla.org/binaryinputstream;1");
|
||||
if (!objectInput)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
stringStream->AdoptData(buffer, len);
|
||||
objectInput->SetInputStream(stringStream);
|
||||
|
||||
NS_ADDREF(*stream = objectInput);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// This is questionable API name and design, but we can't
|
||||
// retrieve the wrapped stream from the objectOutputStream later...
|
||||
nsresult
|
||||
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
||||
nsIStorageStream** stream)
|
||||
{
|
||||
nsCOMPtr<nsIStorageStream> storageStream;
|
||||
nsresult rv = NS_NewStorageStream(256, (PRUint32)-1,
|
||||
getter_AddRefs(storageStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput
|
||||
= do_CreateInstance("@mozilla.org/binaryoutputstream;1");
|
||||
if (!objectOutput)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream
|
||||
= do_QueryInterface(storageStream);
|
||||
|
||||
objectOutput->SetOutputStream(outputStream);
|
||||
NS_ADDREF(*wrapperStream = objectOutput);
|
||||
NS_ADDREF(*stream = storageStream);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
|
||||
char** buffer, int* len)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
PRUint32 avail, read;
|
||||
rv = inputStream->Available(&avail);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
char* temp = new char[avail];
|
||||
if (!temp)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
rv = inputStream->Read(temp, avail, &read);
|
||||
if (NS_SUCCEEDED(rv) && avail != read)
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
delete temp;
|
||||
return rv;
|
||||
}
|
||||
|
||||
*len = avail;
|
||||
*buffer = temp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
53
startupcache/test/Makefile.in
Normal file
53
startupcache/test/Makefile.in
Normal file
@ -0,0 +1,53 @@
|
||||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla.org.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Benedict Hsieh <bhsieh@mozilla.com>
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = test_startupcache
|
||||
|
||||
CPP_UNIT_TESTS = TestStartupCache.cpp
|
||||
|
||||
EXTRA_DSO_LIBS += xul
|
||||
LIBS += $(MOZ_COMPONENT_LIBS)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
332
startupcache/test/TestStartupCache.cpp
Normal file
332
startupcache/test/TestStartupCache.cpp
Normal file
@ -0,0 +1,332 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Startup Cache.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "TestHarness.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIClassInfo.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISerializable.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIStartupCache.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsStringAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace scache {
|
||||
|
||||
NS_IMPORT nsresult
|
||||
NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
|
||||
nsIObjectInputStream** stream);
|
||||
|
||||
// We can't retrieve the wrapped stream from the objectOutputStream later,
|
||||
// so we return it here.
|
||||
NS_IMPORT nsresult
|
||||
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
||||
nsIStorageStream** stream);
|
||||
|
||||
NS_IMPORT nsresult
|
||||
NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
|
||||
char** buffer, PRUint32* len);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace mozilla::scache;
|
||||
|
||||
#define NS_ENSURE_STR_MATCH(str1, str2, testname) \
|
||||
PR_BEGIN_MACRO \
|
||||
if (0 != strcmp(str1, str2)) { \
|
||||
fail("failed " testname); \
|
||||
return NS_ERROR_FAILURE; \
|
||||
} \
|
||||
passed("passed " testname); \
|
||||
PR_END_MACRO
|
||||
|
||||
nsresult
|
||||
WaitForStartupTimer() {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStartupCache> sc
|
||||
= do_GetService("@mozilla.org/startupcache/cache;1");
|
||||
PR_Sleep(10 * PR_TicksPerSecond());
|
||||
|
||||
PRBool complete;
|
||||
while (true) {
|
||||
NS_ProcessPendingEvents(nsnull);
|
||||
rv = sc->StartupWriteComplete(&complete);
|
||||
if (NS_FAILED(rv) || complete)
|
||||
break;
|
||||
PR_Sleep(1 * PR_TicksPerSecond());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestStartupWriteRead() {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStartupCache> sc
|
||||
= do_GetService("@mozilla.org/startupcache/cache;1", &rv);
|
||||
if (!sc) {
|
||||
fail("didn't get a pointer...");
|
||||
return NS_ERROR_FAILURE;
|
||||
} else {
|
||||
passed("got a pointer?");
|
||||
}
|
||||
sc->InvalidateCache();
|
||||
|
||||
char* buf = "Market opportunities for BeardBook";
|
||||
char* id = "id";
|
||||
char* outbufPtr = NULL;
|
||||
nsAutoArrayPtr<char> outbuf;
|
||||
PRUint32 len;
|
||||
|
||||
rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = sc->GetBuffer(id, &outbufPtr, &len);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
outbuf = outbufPtr;
|
||||
NS_ENSURE_STR_MATCH(buf, outbuf, "pre-write read");
|
||||
|
||||
rv = WaitForStartupTimer();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = sc->GetBuffer(id, &outbufPtr, &len);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
outbuf = outbufPtr;
|
||||
NS_ENSURE_STR_MATCH(buf, outbuf, "simple write/read");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestWriteInvalidateRead() {
|
||||
nsresult rv;
|
||||
char* buf = "BeardBook competitive analysis";
|
||||
char* id = "id";
|
||||
char* outbuf = NULL;
|
||||
PRUint32 len;
|
||||
nsCOMPtr<nsIStartupCache> sc
|
||||
= do_GetService("@mozilla.org/startupcache/cache;1", &rv);
|
||||
sc->InvalidateCache();
|
||||
|
||||
rv = sc->PutBuffer(id, buf, strlen(buf) + 1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
sc->InvalidateCache();
|
||||
|
||||
rv = sc->GetBuffer(id, &outbuf, &len);
|
||||
delete[] outbuf;
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
passed("buffer not available after invalidate");
|
||||
} else if (NS_SUCCEEDED(rv)) {
|
||||
fail("GetBuffer succeeded unexpectedly after invalidate");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
} else {
|
||||
fail("GetBuffer gave an unexpected failure, expected NOT_AVAILABLE");
|
||||
return rv;
|
||||
}
|
||||
|
||||
sc->InvalidateCache();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestWriteObject() {
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> obj
|
||||
= do_CreateInstance("@mozilla.org/network/simple-uri;1");
|
||||
if (!obj) {
|
||||
fail("did not create object in test write object");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
NS_NAMED_LITERAL_CSTRING(spec, "http://www.mozilla.org");
|
||||
obj->SetSpec(spec);
|
||||
nsCOMPtr<nsIStartupCache> sc = do_GetService("@mozilla.org/startupcache/cache;1", &rv);
|
||||
|
||||
sc->InvalidateCache();
|
||||
|
||||
// Create an object stream. Usually this is done with
|
||||
// NS_NewObjectOutputWrappedStorageStream, but that uses
|
||||
// StartupCache::GetSingleton in debug builds, and we
|
||||
// don't have access to that here. Obviously.
|
||||
char* id = "id";
|
||||
nsCOMPtr<nsIStorageStream> storageStream
|
||||
= do_CreateInstance("@mozilla.org/storagestream;1");
|
||||
NS_ENSURE_ARG_POINTER(storageStream);
|
||||
|
||||
rv = storageStream->Init(256, (PRUint32) -1, nsnull);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput
|
||||
= do_CreateInstance("@mozilla.org/binaryoutputstream;1");
|
||||
if (!objectOutput)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsIOutputStream> outputStream
|
||||
= do_QueryInterface(storageStream);
|
||||
|
||||
rv = objectOutput->SetOutputStream(outputStream);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
fail("failed to create output stream");
|
||||
return rv;
|
||||
}
|
||||
nsCOMPtr<nsISupports> objQI(do_QueryInterface(obj));
|
||||
rv = objectOutput->WriteObject(objQI, PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
fail("failed to write object");
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* bufPtr = NULL;
|
||||
nsAutoArrayPtr<char> buf;
|
||||
PRUint32 len;
|
||||
NS_NewBufferFromStorageStream(storageStream, &bufPtr, &len);
|
||||
buf = bufPtr;
|
||||
|
||||
// Since this is a post-startup write, it should be written and
|
||||
// available.
|
||||
rv = sc->PutBuffer(id, buf, len);
|
||||
if (NS_FAILED(rv)) {
|
||||
fail("failed to insert input stream");
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* buf2Ptr = NULL;
|
||||
nsAutoArrayPtr<char> buf2;
|
||||
PRUint32 len2;
|
||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||
rv = sc->GetBuffer(id, &buf2Ptr, &len2);
|
||||
if (NS_FAILED(rv)) {
|
||||
fail("failed to retrieve buffer");
|
||||
return rv;
|
||||
}
|
||||
buf2 = buf2Ptr;
|
||||
|
||||
rv = NS_NewObjectInputStreamFromBuffer(buf2, len2, getter_AddRefs(objectInput));
|
||||
if (NS_FAILED(rv)) {
|
||||
fail("failed to created input stream");
|
||||
return rv;
|
||||
}
|
||||
buf2.forget();
|
||||
|
||||
nsCOMPtr<nsISupports> deserialized;
|
||||
rv = objectInput->ReadObject(PR_TRUE, getter_AddRefs(deserialized));
|
||||
if (NS_FAILED(rv)) {
|
||||
fail("failed to read object");
|
||||
return rv;
|
||||
}
|
||||
|
||||
PRBool match = false;
|
||||
nsCOMPtr<nsIURI> uri(do_QueryInterface(deserialized));
|
||||
if (uri) {
|
||||
nsCString outSpec;
|
||||
uri->GetSpec(outSpec);
|
||||
match = outSpec.Equals(spec);
|
||||
}
|
||||
if (!match) {
|
||||
fail("deserialized object has incorrect information");
|
||||
return rv;
|
||||
}
|
||||
|
||||
passed("write object");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
TestEarlyShutdown() {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIStartupCache> sc
|
||||
= do_GetService("@mozilla.org/startupcache/cache;1", &rv);
|
||||
sc->InvalidateCache();
|
||||
|
||||
char* buf = "Find your soul beardmate on BeardBook";
|
||||
char* id = "id";
|
||||
PRUint32 len;
|
||||
char* outbuf = NULL;
|
||||
|
||||
sc->ResetStartupWriteTimer();
|
||||
rv = sc->PutBuffer(buf, id, strlen(buf) + 1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIObserver> obs;
|
||||
sc->GetObserver(getter_AddRefs(obs));
|
||||
obs->Observe(nsnull, "xpcom-shutdown", nsnull);
|
||||
rv = WaitForStartupTimer();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = sc->GetBuffer(id, &outbuf, &len);
|
||||
delete[] outbuf;
|
||||
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
passed("buffer not available after early shutdown");
|
||||
} else if (NS_SUCCEEDED(rv)) {
|
||||
fail("GetBuffer succeeded unexpectedly after early shutdown");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
} else {
|
||||
fail("GetBuffer gave an unexpected failure, expected NOT_AVAILABLE");
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int rv = 0;
|
||||
nsresult rv2;
|
||||
ScopedXPCOM xpcom("Startup Cache");
|
||||
|
||||
if (NS_FAILED(TestStartupWriteRead()))
|
||||
rv = 1;
|
||||
if (NS_FAILED(TestWriteInvalidateRead()))
|
||||
rv = 1;
|
||||
if (NS_FAILED(TestWriteObject()))
|
||||
rv = 1;
|
||||
if (NS_FAILED(TestEarlyShutdown()))
|
||||
rv = 1;
|
||||
|
||||
return rv;
|
||||
}
|
@ -139,6 +139,7 @@ COMPONENT_LIBS += \
|
||||
i18n \
|
||||
chardet \
|
||||
jar$(VERSION_NUMBER) \
|
||||
startupcache \
|
||||
pref \
|
||||
htmlpars \
|
||||
imglib2 \
|
||||
|
@ -241,6 +241,7 @@
|
||||
AUTH_MODULE \
|
||||
MODULE(nsJarModule) \
|
||||
ZIPWRITER_MODULE \
|
||||
MODULE(StartupCacheModule) \
|
||||
MODULE(nsPrefModule) \
|
||||
RDF_MODULES \
|
||||
MODULE(nsParserModule) \
|
||||
|
@ -779,6 +779,10 @@ MAKEFILES_extensions="
|
||||
extensions/pref/autoconfig/src/Makefile
|
||||
"
|
||||
|
||||
MAKEFILES_startupcache="
|
||||
startupcache/Makefile
|
||||
"
|
||||
|
||||
add_makefiles "
|
||||
$MAKEFILES_db
|
||||
$MAKEFILES_dom
|
||||
@ -820,6 +824,7 @@ add_makefiles "
|
||||
$MAKEFILES_libmar
|
||||
$MAKEFILES_lib7z
|
||||
$MAKEFILES_extensions
|
||||
$MAKEFILES_startupcache
|
||||
"
|
||||
|
||||
#
|
||||
@ -926,6 +931,7 @@ if [ "$ENABLE_TESTS" ]; then
|
||||
parser/htmlparser/tests/mochitest/Makefile
|
||||
parser/xml/test/Makefile
|
||||
rdf/tests/triplescat/Makefile
|
||||
startupcache/tests/Makefile
|
||||
testing/mochitest/Makefile
|
||||
testing/mochitest/MochiKit/Makefile
|
||||
testing/mochitest/chrome/Makefile
|
||||
|
@ -240,6 +240,10 @@ tier_platform_dirs += embedding/browser/gtk
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef MOZ_ENABLE_LIBXUL
|
||||
tier_platform_dirs += startupcache
|
||||
endif
|
||||
|
||||
ifndef BUILD_STATIC_LIBS
|
||||
tier_platform_dirs += toolkit/library
|
||||
endif
|
||||
|
@ -2491,6 +2491,9 @@ static void RemoveComponentRegistries(nsIFile* aProfileDir, nsIFile* aLocalProfi
|
||||
|
||||
file->SetNativeLeafName(NS_LITERAL_CSTRING("XPC" PLATFORM_FASL_SUFFIX));
|
||||
file->Remove(PR_FALSE);
|
||||
|
||||
file->SetNativeLeafName(NS_LITERAL_CSTRING("startupCache"));
|
||||
file->Remove(PR_TRUE);
|
||||
}
|
||||
|
||||
// To support application initiated restart via nsIAppStartup.quit, we
|
||||
|
@ -147,6 +147,10 @@ extern nsresult nsStringInputStreamConstructor(nsISupports *, REFNSIID, void **)
|
||||
#include "nsChromeRegistry.h"
|
||||
#include "nsChromeProtocolHandler.h"
|
||||
|
||||
#ifdef MOZ_ENABLE_LIBXUL
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_IPC
|
||||
#include "base/at_exit.h"
|
||||
#include "base/command_line.h"
|
||||
@ -542,6 +546,9 @@ NS_InitXPCOM2(nsIServiceManager* *result,
|
||||
// to the directory service.
|
||||
nsDirectoryService::gService->RegisterCategoryProviders();
|
||||
|
||||
#ifdef MOZ_ENABLE_LIBXUL
|
||||
mozilla::scache::StartupCache::GetSingleton();
|
||||
#endif
|
||||
NS_TIME_FUNCTION_MARK("Next: create services from category");
|
||||
|
||||
// Notify observers of xpcom autoregistration start
|
||||
@ -619,7 +626,9 @@ ShutdownXPCOM(nsIServiceManager* servMgr)
|
||||
}
|
||||
|
||||
NS_ProcessPendingEvents(thread);
|
||||
|
||||
#ifdef MOZ_ENABLE_LIBXUL
|
||||
mozilla::scache::StartupCache::DeleteSingleton();
|
||||
#endif
|
||||
if (observerService)
|
||||
(void) observerService->
|
||||
NotifyObservers(nsnull, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID,
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "nsIDirectoryService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIProperties.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
@ -341,7 +342,8 @@ class ScopedXPCOM : public nsIDirectoryServiceProvider2
|
||||
|
||||
// Otherwise, the test harness provides some directories automatically.
|
||||
if (0 == strcmp(aProperty, NS_APP_USER_PROFILE_50_DIR) ||
|
||||
0 == strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR)) {
|
||||
0 == strcmp(aProperty, NS_APP_USER_PROFILE_LOCAL_50_DIR) ||
|
||||
0 == strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
|
||||
nsCOMPtr<nsIFile> profD = GetProfileDirectory();
|
||||
NS_ENSURE_TRUE(profD, NS_ERROR_FAILURE);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user