Commit e5780917 authored by Jan Varga's avatar Jan Varga
Browse files

Bug 1182987 - Part 3: Add "cleanup" transaction with disabled quota checks and...

Bug 1182987 - Part 3: Add "cleanup" transaction with disabled quota checks and vacuuming/checkpointing after commit; r=baku
parent 7bb929b8
Loading
Loading
Loading
Loading
+136 −3
Original line number Diff line number Diff line
@@ -4916,6 +4916,8 @@ private:
  nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
    mCachedStatements;
  RefPtr<UpdateRefcountFunction> mUpdateRefcountFunction;
  RefPtr<QuotaObject> mQuotaObject;
  RefPtr<QuotaObject> mJournalQuotaObject;
  bool mInReadTransaction;
  bool mInWriteTransaction;
@@ -4992,6 +4994,12 @@ public:
  void
  Close();
  nsresult
  DisableQuotaChecks();
  void
  EnableQuotaChecks();
private:
  DatabaseConnection(mozIStorageConnection* aStorageConnection,
                     FileManager* aFileManager);
@@ -5013,6 +5021,9 @@ private:
                            uint32_t aFreelistCount,
                            bool aNeedsCheckpoint,
                            bool* aFreedSomePages);
  nsresult
  GetFileSize(const nsAString& aPath, int64_t* aResult);
};
class MOZ_STACK_CLASS DatabaseConnection::AutoSavepoint final
@@ -10467,6 +10478,106 @@ DatabaseConnection::Close()
  mFileManager = nullptr;
}
nsresult
DatabaseConnection::DisableQuotaChecks()
{
  AssertIsOnConnectionThread();
  MOZ_ASSERT(mStorageConnection);
  if (!mQuotaObject) {
    MOZ_ASSERT(!mJournalQuotaObject);
    nsresult rv = mStorageConnection->GetQuotaObjects(
                                           getter_AddRefs(mQuotaObject),
                                           getter_AddRefs(mJournalQuotaObject));
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
    MOZ_ASSERT(mQuotaObject);
    MOZ_ASSERT(mJournalQuotaObject);
  }
  mQuotaObject->DisableQuotaCheck();
  mJournalQuotaObject->DisableQuotaCheck();
  return NS_OK;
}
void
DatabaseConnection::EnableQuotaChecks()
{
  AssertIsOnConnectionThread();
  MOZ_ASSERT(mQuotaObject);
  MOZ_ASSERT(mJournalQuotaObject);
  RefPtr<QuotaObject> quotaObject;
  RefPtr<QuotaObject> journalQuotaObject;
  mQuotaObject.swap(quotaObject);
  mJournalQuotaObject.swap(journalQuotaObject);
  quotaObject->EnableQuotaCheck();
  journalQuotaObject->EnableQuotaCheck();
  int64_t fileSize;
  nsresult rv = GetFileSize(quotaObject->Path(), &fileSize);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return;
  }
  int64_t journalFileSize;
  rv = GetFileSize(journalQuotaObject->Path(), &journalFileSize);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return;
  }
  DebugOnly<bool> result =
    journalQuotaObject->MaybeUpdateSize(journalFileSize, /* aTruncate */ true);
  MOZ_ASSERT(result);
  result = quotaObject->MaybeUpdateSize(fileSize, /* aTruncate */ true);
  MOZ_ASSERT(result);
}
nsresult
DatabaseConnection::GetFileSize(const nsAString& aPath, int64_t* aResult)
{
  MOZ_ASSERT(!aPath.IsEmpty());
  MOZ_ASSERT(aResult);
  nsresult rv;
  nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }
  rv = file->InitWithPath(aPath);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }
  int64_t fileSize;
  bool exists;
  rv = file->Exists(&exists);
  if (NS_WARN_IF(NS_FAILED(rv))) {
    return rv;
  }
  if (exists) {
    rv = file->GetFileSize(&fileSize);
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  } else {
    fileSize = 0;
  }
  *aResult = fileSize;
  return NS_OK;
}
DatabaseConnection::
CachedStatement::CachedStatement()
#ifdef DEBUG
@@ -10561,6 +10672,7 @@ AutoSavepoint::~AutoSavepoint()
    MOZ_ASSERT(mDEBUGTransaction->GetMode() == IDBTransaction::READ_WRITE ||
               mDEBUGTransaction->GetMode() ==
                 IDBTransaction::READ_WRITE_FLUSH ||
               mDEBUGTransaction->GetMode() == IDBTransaction::CLEANUP ||
               mDEBUGTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
    if (NS_FAILED(mConnection->RollbackSavepoint())) {
@@ -10576,6 +10688,7 @@ AutoSavepoint::Start(const TransactionBase* aTransaction)
  MOZ_ASSERT(aTransaction);
  MOZ_ASSERT(aTransaction->GetMode() == IDBTransaction::READ_WRITE ||
             aTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH ||
             aTransaction->GetMode() == IDBTransaction::CLEANUP ||
             aTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
  DatabaseConnection* connection = aTransaction->GetDatabase()->GetConnection();
@@ -13779,7 +13892,8 @@ Database::AllocPBackgroundIDBTransactionParent(
  if (NS_WARN_IF(aMode != IDBTransaction::READ_ONLY &&
                 aMode != IDBTransaction::READ_WRITE &&
                 aMode != IDBTransaction::READ_WRITE_FLUSH)) {
                 aMode != IDBTransaction::READ_WRITE_FLUSH &&
                 aMode != IDBTransaction::CLEANUP)) {
    ASSERT_UNLESS_FUZZING();
    return nullptr;
  }
@@ -13787,7 +13901,8 @@ Database::AllocPBackgroundIDBTransactionParent(
  // If this is a readwrite transaction to a chrome database make sure the child
  // has write access.
  if (NS_WARN_IF((aMode == IDBTransaction::READ_WRITE ||
                  aMode == IDBTransaction::READ_WRITE_FLUSH) &&
                  aMode == IDBTransaction::READ_WRITE_FLUSH ||
                  aMode == IDBTransaction::CLEANUP) &&
                 mPrincipalInfo.type() == PrincipalInfo::TSystemPrincipalInfo &&
                 !mChromeWriteAccessAllowed)) {
    return nullptr;
@@ -13852,7 +13967,8 @@ Database::RecvPBackgroundIDBTransactionConstructor(
  MOZ_ASSERT(!aObjectStoreNames.IsEmpty());
  MOZ_ASSERT(aMode == IDBTransaction::READ_ONLY ||
             aMode == IDBTransaction::READ_WRITE ||
             aMode == IDBTransaction::READ_WRITE_FLUSH);
             aMode == IDBTransaction::READ_WRITE_FLUSH ||
             aMode == IDBTransaction::CLEANUP);
  MOZ_ASSERT(!mClosed);
  if (IsInvalidated()) {
@@ -14012,6 +14128,13 @@ StartTransactionOp::DoDatabaseWork(DatabaseConnection* aConnection)
  Transaction()->SetActiveOnConnectionThread();
  if (Transaction()->GetMode() == IDBTransaction::CLEANUP) {
    nsresult rv = aConnection->DisableQuotaChecks();
    if (NS_WARN_IF(NS_FAILED(rv))) {
      return rv;
    }
  }
  if (Transaction()->GetMode() != IDBTransaction::READ_ONLY) {
    nsresult rv = aConnection->BeginWriteTransaction();
    if (NS_WARN_IF(NS_FAILED(rv))) {
@@ -14308,6 +14431,7 @@ TransactionBase::VerifyRequestParams(const RequestParams& aParams) const
    case RequestParams::TObjectStoreDeleteParams: {
      if (NS_WARN_IF(mMode != IDBTransaction::READ_WRITE &&
                     mMode != IDBTransaction::READ_WRITE_FLUSH &&
                     mMode != IDBTransaction::CLEANUP &&
                     mMode != IDBTransaction::VERSION_CHANGE)) {
        ASSERT_UNLESS_FUZZING();
        return false;
@@ -14331,6 +14455,7 @@ TransactionBase::VerifyRequestParams(const RequestParams& aParams) const
    case RequestParams::TObjectStoreClearParams: {
      if (NS_WARN_IF(mMode != IDBTransaction::READ_WRITE &&
                     mMode != IDBTransaction::READ_WRITE_FLUSH &&
                     mMode != IDBTransaction::CLEANUP &&
                     mMode != IDBTransaction::VERSION_CHANGE)) {
        ASSERT_UNLESS_FUZZING();
        return false;
@@ -22520,6 +22645,7 @@ CommitOp::WriteAutoIncrementCounts()
  mTransaction->AssertIsOnConnectionThread();
  MOZ_ASSERT(mTransaction->GetMode() == IDBTransaction::READ_WRITE ||
             mTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH ||
             mTransaction->GetMode() == IDBTransaction::CLEANUP ||
             mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
  const nsTArray<RefPtr<FullObjectStoreMetadata>>& metadataArray =
@@ -22587,6 +22713,7 @@ CommitOp::CommitOrRollbackAutoIncrementCounts()
  mTransaction->AssertIsOnConnectionThread();
  MOZ_ASSERT(mTransaction->GetMode() == IDBTransaction::READ_WRITE ||
             mTransaction->GetMode() == IDBTransaction::READ_WRITE_FLUSH ||
             mTransaction->GetMode() == IDBTransaction::CLEANUP ||
             mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE);
  nsTArray<RefPtr<FullObjectStoreMetadata>>& metadataArray =
@@ -22718,6 +22845,12 @@ CommitOp::Run()
      CommitOrRollbackAutoIncrementCounts();
      connection->FinishWriteTransaction();
      if (mTransaction->GetMode() == IDBTransaction::CLEANUP) {
        connection->DoIdleProcessing(/* aNeedsCheckpoint */ true);
        connection->EnableQuotaChecks();
      }
    }
  }
+2 −1
Original line number Diff line number Diff line
@@ -589,7 +589,8 @@ IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
    return nullptr;
  }

  if (IsSourceDeleted() ||
  if (mTransaction->GetMode() == IDBTransaction::CLEANUP ||
      IsSourceDeleted() ||
      !mHaveValue ||
      mType == Type_ObjectStoreKey ||
      mType == Type_IndexKey) {
+12 −2
Original line number Diff line number Diff line
@@ -609,7 +609,8 @@ IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames,

  aRv.MightThrowJSException();

  if (aMode == IDBTransactionMode::Readwriteflush &&
  if ((aMode == IDBTransactionMode::Readwriteflush ||
       aMode == IDBTransactionMode::Cleanup) &&
      !IndexedDatabaseManager::ExperimentalFeaturesEnabled()) {
    // Pretend that this mode doesn't exist. We don't have a way to annotate
    // certain enum values as depending on preferences so we just duplicate the
@@ -651,7 +652,8 @@ IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames,
{
  AssertIsOnOwningThread();

  if (NS_WARN_IF(aMode == IDBTransactionMode::Readwriteflush &&
  if (NS_WARN_IF((aMode == IDBTransactionMode::Readwriteflush ||
                  aMode == IDBTransactionMode::Cleanup) &&
                 !IndexedDatabaseManager::ExperimentalFeaturesEnabled())) {
    IDB_REPORT_INTERNAL_ERR();
    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
@@ -729,6 +731,9 @@ IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames,
    case IDBTransactionMode::Readwriteflush:
      mode = IDBTransaction::READ_WRITE_FLUSH;
      break;
    case IDBTransactionMode::Cleanup:
      mode = IDBTransaction::CLEANUP;
      break;
    case IDBTransactionMode::Versionchange:
      return NS_ERROR_DOM_INVALID_ACCESS_ERR;

@@ -761,6 +766,10 @@ IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames,

  transaction->SetBackgroundActor(actor);

  if (aMode == IDBTransactionMode::Cleanup) {
    ExpireFileActors(/* aExpireAll */ true);
  }

  transaction.forget(aTransaction);
  return NS_OK;
}
@@ -906,6 +915,7 @@ IDBDatabase::AbortTransactions(bool aShouldWarn)
            // We warn for any transactions that could have written data.
            case IDBTransaction::READ_WRITE:
            case IDBTransaction::READ_WRITE_FLUSH:
            case IDBTransaction::CLEANUP:
            case IDBTransaction::VERSION_CHANGE:
              transactionsThatNeedWarning.AppendElement(transaction);
              break;
+2 −1
Original line number Diff line number Diff line
@@ -1296,7 +1296,8 @@ IDBObjectStore::AddOrPut(JSContext* aCx,
  MOZ_ASSERT(aCx);
  MOZ_ASSERT_IF(aFromCursor, aOverwrite);

  if (mDeletedSpec) {
  if (mTransaction->GetMode() == IDBTransaction::CLEANUP ||
      mDeletedSpec) {
    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
    return nullptr;
  }
+5 −1
Original line number Diff line number Diff line
@@ -216,7 +216,8 @@ IDBTransaction::Create(IDBDatabase* aDatabase,
  MOZ_ASSERT(!aObjectStoreNames.IsEmpty());
  MOZ_ASSERT(aMode == READ_ONLY ||
             aMode == READ_WRITE ||
             aMode == READ_WRITE_FLUSH);
             aMode == READ_WRITE_FLUSH ||
             aMode == CLEANUP);

  RefPtr<IDBTransaction> transaction =
    new IDBTransaction(aDatabase, aObjectStoreNames, aMode);
@@ -838,6 +839,9 @@ IDBTransaction::GetMode(ErrorResult& aRv) const
    case READ_WRITE_FLUSH:
      return IDBTransactionMode::Readwriteflush;

    case CLEANUP:
      return IDBTransactionMode::Cleanup;

    case VERSION_CHANGE:
      return IDBTransactionMode::Versionchange;

Loading