Bug 334675 r=darin a=mconnor Notify users on async IO errors

This commit is contained in:
brettw%gmail.com 2006-07-25 17:04:48 +00:00
parent ccce510651
commit 0653b5c604
4 changed files with 135 additions and 1 deletions

View File

@ -0,0 +1,37 @@
# ***** 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 Storage code.
#
# The Initial Developer of the Original Code is Google Inc.
# Portions created by the Initial Developer are Copyright (C) 2006
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Brett Wilson <brettw@gmail.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 *****
storageWriteError=There was an error writing data to the disk. This error is sometimes caused by a full disk.\n\nPlease restart this application

View File

@ -25,3 +25,4 @@
locale/@AB_CD@/global-platform/win/accessible.properties (%chrome/accessibility/win/accessible.properties)
locale/@AB_CD@/global-platform/mac/accessible.properties (%chrome/accessibility/mac/accessible.properties)
locale/@AB_CD@/global-platform/unix/accessible.properties (%chrome/accessibility/unix/accessible.properties)
locale/@AB_CD@/global/storage.properties (%chrome/storage.properties)

View File

@ -51,6 +51,8 @@ GRE_MODULE = 1
LIBXUL_LIBRARY = 1
REQUIRES = xpcom \
intl \
necko \
string \
sqlite3 \
js \

View File

@ -232,11 +232,16 @@
#include "mozStorageService.h"
#include "nsAutoLock.h"
#include "nsThreadUtils.h"
#include "nsIConsoleService.h"
#include "nsIPrompt.h"
#include "nsIRunnable.h"
#include "nsIStringBundle.h"
#include "nsIThread.h"
#include "nsMemory.h"
#include "nsNetCID.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCIDInternal.h"
#include "plstr.h"
#include "prlock.h"
#include "prcvar.h"
@ -264,9 +269,19 @@
// AsyncOsFile
//
// This is a wrapper around the sqlite interal OsFile.
//
// ======
// DANGER
// ======
//
// This function is allocated on my Alloc(), and NOT by new. This means that
// any C++ objects in here will not get their constructor called.
struct AsyncOsFile : public OsFile
{
// This is the filename of the file when it was opened.
nsCString* mFilename;
// This keeps track of the current file offset. Seek operations change this
// offset instead of actually changing the file because we will do stuff to
// the file in the background. We store this offset for each operation such
@ -402,6 +417,7 @@ static int AppendNewAsyncMessage(AsyncOsFile* aFile, PRUint32 aOp,
sqlite_int64 aOffset, PRInt32 aDataSize,
const char *aData);
static int AsyncWriteError = SQLITE_OK; // set on write error
static void DisplayAsyncWriteError();
// threading
// serializes access to the queue, AsyncWriteThreadInstance = nsnull means
@ -641,6 +657,7 @@ AsyncOpenFile(const char* aName, AsyncOsFile** aFile,
}
memset(*aFile, 0, sizeof(AsyncOsFile));
(*aFile)->mFilename = new nsCString(aName);
(*aFile)->pMethod = &iomethod;
(*aFile)->mOpen = PR_TRUE;
(*aFile)->mBaseRead = aBaseRead;
@ -1323,7 +1340,10 @@ ProcessOneMessage(AsyncMessage* aMessage)
// two handles matters here)
sqliteOrigClose(&aMessage->mFile->mBaseWrite);
sqliteOrigClose(&aMessage->mFile->mBaseRead);
if (aMessage->mFile->mFilename)
delete aMessage->mFile->mFilename;
nsMemory::Free(aMessage->mFile);
aMessage->mFile = nsnull;
break;
case ASYNC_OPENDIRECTORY:
@ -1423,9 +1443,30 @@ ProcessAsyncMessages()
// put it back when it's done
rc = ProcessOneMessage(message);
// check for error
if (rc != SQLITE_OK) {
AsyncWriteError = rc;
NS_NOTREACHED("FILE ERROR");
// log error to console
nsresult rv;
nsCOMPtr<nsIConsoleService> consoleSvc =
do_GetService("@mozilla.org/consoleservice;1", &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Couldn't get the console service for logging file error");
} else {
nsAutoString logMessage;
logMessage.AssignLiteral("mozStorage: error code ");
logMessage.AppendInt(rc);
logMessage.AppendLiteral(" for database ");
if (message->mFile && message->mFile->mFilename)
logMessage.Append(NS_ConvertUTF8toUTF16(*message->mFile->mFilename));
rv = consoleSvc->LogStringMessage(logMessage.get());
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Couldn't log message on async error");
}
// tell user to restart
DisplayAsyncWriteError();
return;
}
@ -1451,3 +1492,56 @@ ProcessAsyncMessages()
#endif
}
}
// nsAsyncWriteErrorDisplayer
//
// This gets dispatched to the main thread so that we can do all the UI
// calls there. The prompt service must be called from the main thread.
class nsAsyncWriteErrorDisplayer : public nsRunnable
{
public:
NS_IMETHOD Run()
{
nsresult rv;
nsCOMPtr<nsIPrompt> prompt = do_CreateInstance(
NS_DEFAULTPROMPT_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStringBundleService> bundleService = do_GetService(
"@mozilla.org/intl/stringbundle;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStringBundle> bundle;
rv = bundleService->CreateBundle(
"chrome://global/locale/storage.properties", getter_AddRefs(bundle));
NS_ENSURE_SUCCESS(rv, rv);
nsXPIDLString message;
rv = bundle->GetStringFromName(NS_LITERAL_STRING("storageWriteError").get(),
getter_Copies(message));
NS_ENSURE_SUCCESS(rv, rv);
return prompt->Alert(nsnull, message.get());
}
};
// DisplayAsyncWriteError
//
// Displays a general message box informing the user of the I/O error. The
// problem is that this is called from the I/O thread, which can't display
// UI. Therefore, we proxy to the UI thread.
void
DisplayAsyncWriteError()
{
nsCOMPtr<nsIRunnable> displayer(new nsAsyncWriteErrorDisplayer);
if (! displayer) {
NS_WARNING("Unable to create displayer");
return;
}
nsresult rv = NS_DispatchToMainThread(displayer);
NS_ASSERTION(NS_SUCCEEDED(rv), "Can't call main thread");
}