Commit 31c8e763 authored by vladimir%pobox.com's avatar vladimir%pobox.com
Browse files

b=334174, corrupted db files are not handled correctly, r=brettw

parent 3d9bf714
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -2726,7 +2726,17 @@ var engineMetadataService = {
    file.append("search.sqlite");
    var dbService = Cc["@mozilla.org/storage/service;1"].
                    getService(Ci.mozIStorageService);
    try {
        this.mDB = dbService.openDatabase(file);
    } catch (ex) {
        if (ex.result == 0x8052000b) { /* NS_ERROR_FILE_CORRUPTED */
            // delete and try again
            file.remove(false);
            this.mDB = dbService.openDatabase(file);
        } else {
            throw ex;
        }
    }

    try {
      this.mDB.createTable("engine_data", engineDataTable);
+6 −0
Original line number Diff line number Diff line
@@ -64,6 +64,12 @@ nsDOMStorageDB::Init()
  service = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
  NS_ENSURE_SUCCESS(rv, rv);
  rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection));
  if (rv == NS_ERROR_FILE_CORRUPTED) {
    // delete the db and try opening again
    rv = storageFile->Remove(PR_FALSE);
    NS_ENSURE_SUCCESS(rv, rv);
    rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection));
  }
  NS_ENSURE_SUCCESS(rv, rv);

  PRBool exists;
+84 −0
Original line number Diff line number Diff line
@@ -363,6 +363,12 @@ struct AsyncMessage
  AsyncMessage* mNext;
};

struct AsyncMessageBarrierData
{
  PRLock *mLock;
  PRCondVar *mCondVar;
};

// Possible values of AsyncMessage.mOp
#define ASYNC_WRITE         1
#define ASYNC_SYNC          2
@@ -373,6 +379,7 @@ struct AsyncMessage
#define ASYNC_DELETE        7
#define ASYNC_OPENEXCLUSIVE 8
#define ASYNC_SYNCDIRECTORY 9
#define ASYNC_BARRIER       10

// replacements for the sqlite OS routines
static int AsyncOpenReadWrite(const char *aName, OsFile **aFile, int *aReadOnly);
@@ -396,6 +403,8 @@ static int AsyncUnlock(OsFile* aFile, int aLockType);
static int AsyncCheckReservedLock(OsFile* aFile);
static int AsyncLockState(OsFile* aFile);

static int AsyncBarrier(PRLock* aLock, PRCondVar* aCondVar);

// backend for all the open functions
static int AsyncOpenFile(const char *aName, AsyncOsFile **aFile,
                     OsFile *aBaseRead, PRBool aOpenForWriting);
@@ -537,6 +546,56 @@ mozStorageService::InitStorageAsyncIO()
  return NS_OK;
}

// mozstorageService::FlushAsyncIO
//
//    This function will grab the async lock and process all
//    remaining async operations that are in the queue on the current
//    thread.  Call this when you need to make sure that an operation
//    has taken place, e.g. that a file has been closed.

nsresult
mozStorageService::FlushAsyncIO()
{
  AsyncMessage *message = 0;
  int rc;

  // single threaded? nothing to do.
  if (!AsyncWriteThreadInstance)
    return NS_OK;

  PRLock *flushLock = PR_NewLock();
  if (!flushLock)
    return NS_ERROR_OUT_OF_MEMORY;

  PRCondVar *flushCond = PR_NewCondVar(flushLock);
  if (!flushCond) {
    PR_DestroyLock(flushLock);
    return NS_ERROR_OUT_OF_MEMORY;
  }

  PR_Lock(flushLock);

  rc = AsyncBarrier(flushLock, flushCond);
  if (rc == SQLITE_OK) {
    // the async thread will notify us once it reaches
    // the ASYNC_BARRIER operation; only wait if
    // adding the barrier worked, otherwise just unlock
    // and return the error
    PR_WaitCondVar(flushCond, PR_INTERVAL_NO_TIMEOUT);
  }

  PR_Unlock(flushLock);

  PR_DestroyCondVar(flushCond);
  PR_DestroyLock(flushLock);

  if (rc == SQLITE_NOMEM)
    return NS_ERROR_OUT_OF_MEMORY;
  else if (rc != SQLITE_OK)
    return NS_ERROR_FAILURE;
  return NS_OK;
}


// mozStorageService::FinishAsyncIO
//
@@ -1275,6 +1334,23 @@ AsyncLockState(OsFile* aFile)
  return SQLITE_OK;
}

// AsyncBarrier
//
//    This is used to notify a waiting thread that this point in the async
//    queue has been reached.  Note that this is not a sqlite redirected IO
//    function

int // static
AsyncBarrier(PRLock* aLock, PRCondVar* aCondVar)
{
  AsyncMessageBarrierData bd;

  bd.mLock = aLock;
  bd.mCondVar = aCondVar;

  return AppendNewAsyncMessage(nsnull, ASYNC_BARRIER, 0,
                               sizeof(AsyncMessageBarrierData), (const char*) &bd);
}

// ProcessOneMessage
//
@@ -1385,6 +1461,14 @@ ProcessOneMessage(AsyncMessage* aMessage)
      break;
    }

    case ASYNC_BARRIER: {
      AsyncMessageBarrierData *bd = (AsyncMessageBarrierData*) aMessage->mBuf;
      PR_Lock(bd->mLock);
      PR_NotifyCondVar(bd->mCondVar);
      PR_Unlock(bd->mLock);
      break;
    }

    default:
      NS_NOTREACHED("Illegal value for AsyncMessage.mOp");
  }
+61 −13
Original line number Diff line number Diff line
@@ -73,7 +73,31 @@ mozStorageConnection::~mozStorageConnection()
        if (srv != SQLITE_OK) {
            NS_WARNING("sqlite3_close failed.  There are probably outstanding statements!");
        }

        // make sure it really got closed
        ((mozStorageService*)(mStorageService.get()))->FlushAsyncIO();
    }
}

// convert a sqlite srv to an nsresult
static nsresult
ConvertResultCode (int srv)
{
    switch (srv) {
        case SQLITE_OK:
            return NS_OK;
        case SQLITE_CORRUPT:
        case SQLITE_NOTADB:
            return NS_ERROR_FILE_CORRUPTED;
        case SQLITE_PERM:
        case SQLITE_CANTOPEN:
            return NS_ERROR_FILE_ACCESS_DENIED;
        case SQLITE_BUSY:
            return NS_ERROR_FILE_IS_LOCKED;
    }

    // generic error
    return NS_ERROR_FAILURE;
}

#ifdef PR_LOGGING
@@ -109,7 +133,7 @@ mozStorageConnection::Initialize(nsIFile *aDatabaseFile)
    }
    if (srv != SQLITE_OK) {
        mDBConn = nsnull;
        return NS_ERROR_FAILURE; // XXX error code
        return ConvertResultCode(srv);
    }

#ifdef PR_LOGGING
@@ -119,6 +143,35 @@ mozStorageConnection::Initialize(nsIFile *aDatabaseFile)
    sqlite3_trace (mDBConn, tracefunc, nsnull);
#endif

    /* Execute a dummy statement to force the db open, and to verify
     * whether it's valid or not
     */
    sqlite3_stmt *stmt = nsnull;
    nsCString query("SELECT * FROM sqlite_master");
    srv = sqlite3_prepare (mDBConn, query.get(), query.Length(), &stmt, nsnull);
 
    if (srv == SQLITE_OK) {
        srv = sqlite3_step(stmt);
 
        if (srv == SQLITE_DONE || srv == SQLITE_ROW)
            srv = SQLITE_OK;
    } else {
        stmt = nsnull;
    }

    if (stmt != nsnull)
        sqlite3_finalize (stmt);
 
    if (srv != SQLITE_OK) {
        sqlite3_close (mDBConn);
        mDBConn = nsnull;

        // make sure it really got closed
        ((mozStorageService*)(mStorageService.get()))->FlushAsyncIO();

        return ConvertResultCode(srv);
    }

    mFunctions = do_CreateInstance(NS_ARRAY_CONTRACTID, &rv);
    if (NS_FAILED(rv)) return rv;

@@ -199,7 +252,7 @@ mozStorageConnection::CreateStatement(const nsACString& aSQLStatement,
    nsresult rv = statement->Initialize (this, aSQLStatement);
    if (NS_FAILED(rv)) {
        NS_RELEASE(statement);
        return NS_ERROR_FAILURE; // XXX error code
        return rv;
    }

    *_retval = statement;
@@ -215,7 +268,7 @@ mozStorageConnection::ExecuteSimpleSQL(const nsACString& aSQLStatement)
                            NULL, NULL, NULL);
    if (srv != SQLITE_OK) {
        HandleSqliteError(nsPromiseFlatCString(aSQLStatement).get());
        return NS_ERROR_FAILURE; // XXX error code
        return ConvertResultCode(srv);
    }

    return NS_OK;
@@ -234,7 +287,7 @@ mozStorageConnection::TableExists(const nsACString& aSQLStatement, PRBool *_retv
    int srv = sqlite3_prepare (mDBConn, query.get(), query.Length(), &stmt, nsnull);
    if (srv != SQLITE_OK) {
        HandleSqliteError(query.get());
        return NS_ERROR_FAILURE; // XXX error code
        return ConvertResultCode(srv);
    }

    PRBool exists = PR_FALSE;
@@ -269,7 +322,7 @@ mozStorageConnection::IndexExists(const nsACString& aIndexName, PRBool* _retval)
    int srv = sqlite3_prepare(mDBConn, query.get(), query.Length(), &stmt, nsnull);
    if (srv != SQLITE_OK) {
        HandleSqliteError(query.get());
        return NS_ERROR_FAILURE; // XXX error code
        return ConvertResultCode(srv);
    }

    PRBool exists = PR_FALSE;
@@ -381,10 +434,7 @@ mozStorageConnection::CreateTable(/*const nsID& aID,*/

    PR_smprintf_free(buf);

    if (srv != SQLITE_OK) {
        return NS_ERROR_FAILURE; // XXX SQL_ERROR_TABLE_EXISTS
    }
    return NS_OK;
    return ConvertResultCode(srv);
}

/**
@@ -433,7 +483,7 @@ mozStorageConnection::CreateFunction(const char *aFunctionName,
                                       nsnull);
    if (srv != SQLITE_OK) {
        HandleSqliteError(nsnull);
        return NS_ERROR_FAILURE;
        return ConvertResultCode(srv);
    }

    rv = mFunctions->AppendElement (aFunction, PR_FALSE);
@@ -450,9 +500,7 @@ nsresult
mozStorageConnection::Preload()
{
  int srv = sqlite3Preload(mDBConn);
  if (srv != SQLITE_OK)
    return NS_ERROR_FAILURE;
  return NS_OK;
  return ConvertResultCode(srv);
}

/**
+5 −0
Original line number Diff line number Diff line
@@ -48,9 +48,13 @@

#include "mozIStorageService.h"

class mozStorageConnection;

class mozStorageService : public mozIStorageService,
                          public nsIObserver
{
    friend class mozStorageConnection;

public:
    mozStorageService();

@@ -71,6 +75,7 @@ protected:
    nsCOMPtr<nsIFile> mProfileStorageFile;

    nsresult InitStorageAsyncIO();
    nsresult FlushAsyncIO();
    nsresult FinishAsyncIO();
    void FreeLocks();
};
Loading