Bug 767493: Make AsyncUsageRunnable participate in the WaitForOpenAllowed synchronization mechanism. r=bent

This commit is contained in:
Kyle Huey 2012-06-22 11:47:05 -07:00
Родитель 66107757ab
Коммит 73b4c531b6
2 изменённых файлов: 127 добавлений и 46 удалений

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

@ -1161,23 +1161,15 @@ IndexedDatabaseManager::GetUsageForURI(
// Non-standard URIs can't create databases anyway so fire the callback
// immediately.
if (origin.EqualsLiteral("null")) {
rv = NS_DispatchToCurrentThread(runnable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
return runnable->TakeShortcut();
}
// See if we're currently clearing the databases for this origin. If so then
// we pretend that we've already deleted everything.
if (IsClearOriginPending(origin)) {
rv = NS_DispatchToCurrentThread(runnable);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// Otherwise dispatch to the IO thread to actually compute the usage.
rv = mIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
// Otherwise put the computation runnable in the queue.
rv = WaitForOpenAllowed(origin, nsnull, runnable);
NS_ENSURE_SUCCESS(rv, rv);
runnable->AdvanceState();
return NS_OK;
}
@ -1477,7 +1469,8 @@ IndexedDatabaseManager::AsyncUsageRunnable::AsyncUsageRunnable(
mCallback(aCallback),
mUsage(0),
mFileUsage(0),
mCanceled(0)
mCanceled(0),
mCallbackState(Pending)
{
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
NS_ASSERTION(aURI, "Null pointer!");
@ -1506,50 +1499,102 @@ IncrementUsage(PRUint64* aUsage, PRUint64 aDelta)
}
}
nsresult
IndexedDatabaseManager::AsyncUsageRunnable::TakeShortcut()
{
NS_ASSERTION(mCallbackState == Pending, "Huh?");
nsresult rv = NS_DispatchToCurrentThread(this);
NS_ENSURE_SUCCESS(rv, rv);
mCallbackState = Shortcut;
return NS_OK;
}
nsresult
IndexedDatabaseManager::AsyncUsageRunnable::RunInternal()
{
IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
NS_ASSERTION(mgr, "This should never fail!");
if (NS_IsMainThread()) {
// Call the callback unless we were canceled.
if (!mCanceled) {
PRUint64 usage = mUsage;
IncrementUsage(&usage, mFileUsage);
mCallback->OnUsageResult(mURI, usage, mFileUsage);
}
// Clean up.
mURI = nsnull;
mCallback = nsnull;
// And tell the IndexedDatabaseManager that we're done.
mgr->OnUsageCheckComplete(this);
return NS_OK;
}
if (mCanceled) {
return NS_OK;
}
// Get the directory that contains all the database files we care about.
nsCOMPtr<nsIFile> directory;
nsresult rv = mgr->GetDirectoryForOrigin(mOrigin, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
switch (mCallbackState) {
case Pending: {
NS_NOTREACHED("Should never get here without being dispatched!");
return NS_ERROR_UNEXPECTED;
}
bool exists;
rv = directory->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
case OpenAllowed: {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// If the directory exists then enumerate all the files inside, adding up the
// sizes to get the final usage statistic.
if (exists && !mCanceled) {
rv = GetUsageForDirectory(directory, &mUsage);
NS_ENSURE_SUCCESS(rv, rv);
AdvanceState();
if (NS_FAILED(mgr->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL))) {
NS_WARNING("Failed to dispatch to the IO thread!");
}
return NS_OK;
}
case IO: {
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
AdvanceState();
// Get the directory that contains all the database files we care about.
nsCOMPtr<nsIFile> directory;
nsresult rv = mgr->GetDirectoryForOrigin(mOrigin, getter_AddRefs(directory));
NS_ENSURE_SUCCESS(rv, rv);
bool exists;
rv = directory->Exists(&exists);
NS_ENSURE_SUCCESS(rv, rv);
// If the directory exists then enumerate all the files inside, adding up the
// sizes to get the final usage statistic.
if (exists && !mCanceled) {
rv = GetUsageForDirectory(directory, &mUsage);
NS_ENSURE_SUCCESS(rv, rv);
}
// Run dispatches us back to the main thread.
return NS_OK;
}
case Complete: // Fall through
case Shortcut: {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
// Call the callback unless we were canceled.
if (!mCanceled) {
PRUint64 usage = mUsage;
IncrementUsage(&usage, mFileUsage);
mCallback->OnUsageResult(mURI, usage, mFileUsage);
}
// Clean up.
mURI = nsnull;
mCallback = nsnull;
// And tell the IndexedDatabaseManager that we're done.
mgr->OnUsageCheckComplete(this);
if (mCallbackState == Complete) {
mgr->AllowNextSynchronizedOp(mOrigin, nsnull);
}
return NS_OK;
}
default:
NS_ERROR("Unknown state value!");
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
NS_NOTREACHED("Should never get here!");
return NS_ERROR_UNEXPECTED;
}
nsresult
@ -1625,7 +1670,6 @@ IndexedDatabaseManager::AsyncUsageRunnable::Run()
}
}
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}

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

@ -290,6 +290,22 @@ private:
// IndexedDatabaseManager that the job has been completed.
class AsyncUsageRunnable MOZ_FINAL : public nsIRunnable
{
enum CallbackState {
// Not yet run.
Pending = 0,
// Running on the main thread in the callback for OpenAllowed.
OpenAllowed,
// Running on the IO thread.
IO,
// Running on the main thread after all work is done.
Complete,
// Running on the main thread after skipping the work
Shortcut
};
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIRUNNABLE
@ -301,6 +317,25 @@ private:
// Sets the canceled flag so that the callback is never called.
void Cancel();
void AdvanceState()
{
switch (mCallbackState) {
case Pending:
mCallbackState = OpenAllowed;
return;
case OpenAllowed:
mCallbackState = IO;
return;
case IO:
mCallbackState = Complete;
return;
default:
NS_NOTREACHED("Can't advance past Complete!");
}
}
nsresult TakeShortcut();
// Run calls the RunInternal method and makes sure that we always dispatch
// to the main thread in case of an error.
inline nsresult RunInternal();
@ -310,10 +345,12 @@ private:
nsCOMPtr<nsIURI> mURI;
nsCString mOrigin;
nsCOMPtr<nsIIndexedDatabaseUsageCallback> mCallback;
PRUint64 mUsage;
PRUint64 mFileUsage;
PRInt32 mCanceled;
CallbackState mCallbackState;
};
// Called when AsyncUsageRunnable has finished its Run() method.