DomStorage: Make DomStorageDatabaseFactory async and rollout-aware [chromium/src : main]

0 views
Skip to first unread message

Steve Becker (Gerrit)

unread,
Jun 4, 2026, 5:59:37 PMJun 4
to Rahul Singh, Xiaohan Zhao, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
Attention needed from Rahul Singh and Xiaohan Zhao

Steve Becker added 6 comments

File components/services/storage/dom_storage/dom_storage_database.cc
Line 252, Patchset 5 (Latest): base::ThreadPool::PostTaskAndReplyWithResult(
Steve Becker . unresolved

Can we use the LevelDB's task runner for this?

`GetTaskRunnerForDb(path)`

That will avoid a race where we're checking this while other operations are in flight. While this is unlikely, it could happen if a user closes the browser profile and then re-opens it.

Line 256, Patchset 5 (Latest): base::BindOnce(&DomStorageDatabaseFactory::OnDiskStateChecked,
Steve Becker . unresolved

This delays Open(), while some delay is unavoidable since we're doing extra work, maybe we can minimize the delay by doing more work in the task that checks the leveldbstate. That task could:

1. Check the level db state.
2. Create the right database based on the result.
3. Call the async Open() operation.
4. The factory create callback should run after open completes.

Maybe we can rename DomStorageDatabaseFactory::Create to Open. It's confusing that we have two create callbacks (CreateCallback and CreateResultCallback) and three Create functions, Create, CreateImpl and CreateDatabase(). Maybe we can end up with just Open/OpenImp and CreateDatabase() instead?

For this plan, we'll have to take care that everything ends up on running on the right sequence. You can use BindPostTask on the callback to make sure it runs in the expected place.

Line 318, Patchset 5 (Latest): base::ThreadPool::PostTaskAndReplyWithResult(
Steve Becker . unresolved

Same as Create above, can we use the LevelDB's task runner for this?

`GetTaskRunnerForDb(path)`

Line 355, Patchset 5 (Latest): std::string basename = database_path.BaseName().MaybeAsASCII();
bool is_sqlite = (basename == "LocalStorage" || basename == "SessionStorage");
Steve Becker . unresolved

Should the caller pass this parameter instead? This is fragile if the path constant changes. It also duplicates logic.

File components/services/storage/dom_storage/session_storage_impl.cc
Line 700, Patchset 5 (Latest): base::BindOnce(&SessionStorageImpl::OnDiskStateCleared,
Steve Becker . unresolved

We should try to avoid waiting for deletion if possible. It puts us into a weird state where database_ is nullptr while waiting for the delete to finish. Maybe we can add a flag to the proposed DomStorageDatabaseFactory::Open (see other comments) that will kick off the deletion before creating and opening the database.

File content/browser/dom_storage/dom_storage_context_wrapper.cc
Line 117, Patchset 5 (Latest): // TODO(crbug.com/377242771): Move this histogram to
Steve Becker . unresolved

Let's make a new bug for this so it does not get lost.

Open in Gerrit

Related details

Attention is currently required from:
  • Rahul Singh
  • Xiaohan Zhao
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
Gerrit-Change-Number: 7877569
Gerrit-PatchSet: 5
Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-CC: James Maclean <wjma...@chromium.org>
Gerrit-Attention: Rahul Singh <rah...@microsoft.com>
Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-Comment-Date: Thu, 04 Jun 2026 21:59:24 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Xiaohan Zhao (Gerrit)

unread,
Jun 11, 2026, 12:18:38 PMJun 11
to Rahul Singh, Steve Becker, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
Attention needed from Rahul Singh

Xiaohan Zhao added 1 comment

File components/services/storage/dom_storage/dom_storage_database.cc
Line 349, Patchset 9: // If a LevelDB database exists, destroy it. Otherwise destroy the SQLite
// path (which is a no-op if no SQLite database exists either).
base::FilePath path = (leveldb_state != LevelDbOnDiskState::kNone)
? DomStorageDatabase::GetLevelDbPath(
storage_type, storage_partition_dir)
: DomStorageDatabase::GetSqlitePath(
storage_type, storage_partition_dir);
Xiaohan Zhao . unresolved

Question: in a normal rollout I think only one active backend should exist, but should we defensively clear both possible backend paths in case a partial clean up leaves both LevelDB and SQLite on disk? Is that possible?

Open in Gerrit

Related details

Attention is currently required from:
  • Rahul Singh
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
Gerrit-Change-Number: 7877569
Gerrit-PatchSet: 11
Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-CC: James Maclean <wjma...@chromium.org>
Gerrit-Attention: Rahul Singh <rah...@microsoft.com>
Gerrit-Comment-Date: Thu, 11 Jun 2026 16:18:26 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
satisfied_requirement
unsatisfied_requirement
open
diffy

Rahul Singh (Gerrit)

unread,
Jun 11, 2026, 1:51:19 PMJun 11
to Xiaohan Zhao, Steve Becker, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org

Rahul Singh voted and added 4 comments

Votes added by Rahul Singh

Commit-Queue+1

4 comments

File components/services/storage/dom_storage/dom_storage_database.cc
Line 252, Patchset 5: base::ThreadPool::PostTaskAndReplyWithResult(
Steve Becker . resolved

Can we use the LevelDB's task runner for this?

`GetTaskRunnerForDb(path)`

That will avoid a race where we're checking this while other operations are in flight. While this is unlikely, it could happen if a user closes the browser profile and then re-opens it.

Rahul Singh

Done

Line 318, Patchset 5: base::ThreadPool::PostTaskAndReplyWithResult(
Steve Becker . resolved

Same as Create above, can we use the LevelDB's task runner for this?

`GetTaskRunnerForDb(path)`

Rahul Singh

Done

Line 355, Patchset 5: std::string basename = database_path.BaseName().MaybeAsASCII();

bool is_sqlite = (basename == "LocalStorage" || basename == "SessionStorage");
Steve Becker . resolved

Should the caller pass this parameter instead? This is fragile if the path constant changes. It also duplicates logic.

Rahul Singh

Done

File content/browser/dom_storage/dom_storage_context_wrapper.cc
Line 117, Patchset 5: // TODO(crbug.com/377242771): Move this histogram to
Steve Becker . resolved

Let's make a new bug for this so it does not get lost.

Rahul Singh

This TODO has been handled in CL5 in this relation chain. See here:
https://chromium-review.googlesource.com/c/chromium/src/+/7919708

Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
Gerrit-Change-Number: 7877569
Gerrit-PatchSet: 11
Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-CC: James Maclean <wjma...@chromium.org>
Gerrit-Comment-Date: Thu, 11 Jun 2026 17:51:09 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Comment-In-Reply-To: Steve Becker <ste...@microsoft.com>
satisfied_requirement
unsatisfied_requirement
open
diffy

Rahul Singh (Gerrit)

unread,
Jun 12, 2026, 2:12:48 PMJun 12
to Xiaohan Zhao, Steve Becker, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
Attention needed from Steve Becker and Xiaohan Zhao

Rahul Singh added 2 comments

File components/services/storage/dom_storage/dom_storage_database.cc
Line 256, Patchset 5: base::BindOnce(&DomStorageDatabaseFactory::OnDiskStateChecked,
Steve Becker . resolved

This delays Open(), while some delay is unavoidable since we're doing extra work, maybe we can minimize the delay by doing more work in the task that checks the leveldbstate. That task could:

1. Check the level db state.
2. Create the right database based on the result.
3. Call the async Open() operation.
4. The factory create callback should run after open completes.

Maybe we can rename DomStorageDatabaseFactory::Create to Open. It's confusing that we have two create callbacks (CreateCallback and CreateResultCallback) and three Create functions, Create, CreateImpl and CreateDatabase(). Maybe we can end up with just Open/OpenImp and CreateDatabase() instead?

For this plan, we'll have to take care that everything ends up on running on the right sequence. You can use BindPostTask on the callback to make sure it runs in the expected place.

Rahul Singh

Great suggestion @ste...@microsoft.com! I took a stab at this in PS 12. PTAL, if it looks good, I'll follow up with an update that address your concern around waiting for deletion. Thank you!

Line 349, Patchset 9: // If a LevelDB database exists, destroy it. Otherwise destroy the SQLite
// path (which is a no-op if no SQLite database exists either).
base::FilePath path = (leveldb_state != LevelDbOnDiskState::kNone)
? DomStorageDatabase::GetLevelDbPath(
storage_type, storage_partition_dir)
: DomStorageDatabase::GetSqlitePath(
storage_type, storage_partition_dir);
Xiaohan Zhao . unresolved

Question: in a normal rollout I think only one active backend should exist, but should we defensively clear both possible backend paths in case a partial clean up leaves both LevelDB and SQLite on disk? Is that possible?

Rahul Singh

Good question! Steve and I previously discussed this. IIRC we settled on this is worth a TODO but not an OnDisk Experiment blocker. @ste...@microsoft.com does that sound accurate?

Open in Gerrit

Related details

Attention is currently required from:
  • Steve Becker
  • Xiaohan Zhao
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
Gerrit-Change-Number: 7877569
Gerrit-PatchSet: 12
Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-CC: James Maclean <wjma...@chromium.org>
Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-Attention: Steve Becker <ste...@microsoft.com>
Gerrit-Comment-Date: Fri, 12 Jun 2026 18:12:38 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Xiaohan Zhao <xiaoh...@microsoft.com>
Comment-In-Reply-To: Steve Becker <ste...@microsoft.com>
satisfied_requirement
unsatisfied_requirement
open
diffy

Steve Becker (Gerrit)

unread,
Jun 16, 2026, 6:53:10 PM (13 days ago) Jun 16
to Rahul Singh, Xiaohan Zhao, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
Attention needed from Rahul Singh and Xiaohan Zhao

Steve Becker added 11 comments

Patchset-level comments
File-level comment, Patchset 14 (Latest):
Steve Becker . resolved

Thanks for iterating. Please let me know if you have any questions.

File components/services/storage/dom_storage/async_dom_storage_database.h
Line 129, Patchset 14 (Latest): // `database_` and `is_sqlite_` must not be used until `is_database_opened_`
Steve Becker . unresolved

nit: Should the `is_sqlite()` accessor above assert that the database is opened?

File components/services/storage/dom_storage/async_dom_storage_database.cc
Line 262, Patchset 14 (Latest): is_database_opened_ = result.open_status.ok();
Steve Becker . unresolved

nit: if `is_database_opened_` is true, should we assert that `database` is valid?

File components/services/storage/dom_storage/dom_storage_database.h
Line 457, Patchset 14 (Latest): OpenResultCallback reply_to_caller);
Steve Becker . unresolved

nit: callback?

Line 435, Patchset 14 (Latest): // Production implementation of Open(). Routes through GetOpenCallback().
Steve Becker . unresolved

nit: I'm not sure if this comment is needed since OpenImpl does not use GetOpenCallback().

Line 426, Patchset 14 (Latest): struct OpenDatabaseParams {
Steve Becker . unresolved

nit: Should we call this `InitializeDatabaseParams` since it's used by InitializeDatabase()?

Line 426, Patchset 14 (Latest): struct OpenDatabaseParams {
Steve Becker . unresolved

nit: Please declare near use.

File components/services/storage/dom_storage/dom_storage_database.cc
Line 223, Patchset 14 (Latest):void DomStorageDatabaseFactory::InitializeDatabase(
OpenDatabaseParams params,
OpenResultCallback reply_to_caller) {
Steve Becker . unresolved

nit: instead of having both InitializeOnDatabaseSequence() and InitializeDatabase(), we could combine these by having InitializeDatabase() get database's the task runner and then post a task to re-run the function if it's not on the database's task runner.

I believe this pattern is used throughout Chromium. That way, the caller of InitializeDatabase() does not need to worry about the calling sequence.

We could also maybe eliminate OpenDatabaseParams since it would only be used once.

Line 256, Patchset 14 (Latest): result.database = base::SequenceBound<std::unique_ptr<DomStorageDatabase>>(
Steve Becker . unresolved
Line 349, Patchset 9: // If a LevelDB database exists, destroy it. Otherwise destroy the SQLite
// path (which is a no-op if no SQLite database exists either).
base::FilePath path = (leveldb_state != LevelDbOnDiskState::kNone)
? DomStorageDatabase::GetLevelDbPath(
storage_type, storage_partition_dir)
: DomStorageDatabase::GetSqlitePath(
storage_type, storage_partition_dir);
Xiaohan Zhao . unresolved

Question: in a normal rollout I think only one active backend should exist, but should we defensively clear both possible backend paths in case a partial clean up leaves both LevelDB and SQLite on disk? Is that possible?

Rahul Singh

Good question! Steve and I previously discussed this. IIRC we settled on this is worth a TODO but not an OnDisk Experiment blocker. @ste...@microsoft.com does that sound accurate?

Steve Becker

For this experiment, I think we should only delete one type of database. This is a good question for our future database migration. To keep things simple, I don't think we should consider the migration successful unless we've deleted the levelDB after migrating to sqlite.

File components/services/storage/dom_storage/local_storage_impl_unittest.cc
Line 1635, Patchset 14 (Latest): GetParam() ? DomStorageSqliteRolloutStage::kUseSqliteForNewDatabases
: DomStorageSqliteRolloutStage::kUseLevelDbAsControl;
Steve Becker . unresolved

Do we have test coverage for kUseLevelDbOnly and kUseSqliteOnly?

Open in Gerrit

Related details

Attention is currently required from:
  • Rahul Singh
  • Xiaohan Zhao
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
Gerrit-Change-Number: 7877569
Gerrit-PatchSet: 14
Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-CC: James Maclean <wjma...@chromium.org>
Gerrit-Attention: Rahul Singh <rah...@microsoft.com>
Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-Comment-Date: Tue, 16 Jun 2026 22:52:52 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Rahul Singh <rah...@microsoft.com>
Comment-In-Reply-To: Xiaohan Zhao <xiaoh...@microsoft.com>
satisfied_requirement
unsatisfied_requirement
open
diffy

Rahul Singh (Gerrit)

unread,
Jun 18, 2026, 2:07:33 AM (12 days ago) Jun 18
to Xiaohan Zhao, Steve Becker, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
Attention needed from Steve Becker and Xiaohan Zhao

Rahul Singh voted and added 11 comments

Votes added by Rahul Singh

Commit-Queue+1

11 comments

File components/services/storage/dom_storage/async_dom_storage_database.h
Line 129, Patchset 14: // `database_` and `is_sqlite_` must not be used until `is_database_opened_`
Steve Becker . resolved

nit: Should the `is_sqlite()` accessor above assert that the database is opened?

Rahul Singh

Done

File components/services/storage/dom_storage/async_dom_storage_database.cc
Line 262, Patchset 14: is_database_opened_ = result.open_status.ok();
Steve Becker . resolved

nit: if `is_database_opened_` is true, should we assert that `database` is valid?

Rahul Singh

Done

File components/services/storage/dom_storage/dom_storage_database.h
Line 457, Patchset 14: OpenResultCallback reply_to_caller);
Steve Becker . resolved

nit: callback?

Rahul Singh

Done

Line 435, Patchset 14: // Production implementation of Open(). Routes through GetOpenCallback().
Steve Becker . resolved

nit: I'm not sure if this comment is needed since OpenImpl does not use GetOpenCallback().

Rahul Singh

Done

Line 426, Patchset 14: struct OpenDatabaseParams {
Steve Becker . resolved

nit: Should we call this `InitializeDatabaseParams` since it's used by InitializeDatabase()?

Rahul Singh

I removed the POD struct

Line 426, Patchset 14: struct OpenDatabaseParams {
Steve Becker . resolved

nit: Please declare near use.

Rahul Singh

Just removed it instead

File components/services/storage/dom_storage/dom_storage_database.cc
Line 223, Patchset 14:void DomStorageDatabaseFactory::InitializeDatabase(
OpenDatabaseParams params,
OpenResultCallback reply_to_caller) {
Steve Becker . resolved

nit: instead of having both InitializeOnDatabaseSequence() and InitializeDatabase(), we could combine these by having InitializeDatabase() get database's the task runner and then post a task to re-run the function if it's not on the database's task runner.

I believe this pattern is used throughout Chromium. That way, the caller of InitializeDatabase() does not need to worry about the calling sequence.

We could also maybe eliminate OpenDatabaseParams since it would only be used once.

Rahul Singh

Done

Line 256, Patchset 14: result.database = base::SequenceBound<std::unique_ptr<DomStorageDatabase>>(
Steve Becker . resolved
Rahul Singh

Done

Line 349, Patchset 9: // If a LevelDB database exists, destroy it. Otherwise destroy the SQLite
// path (which is a no-op if no SQLite database exists either).
base::FilePath path = (leveldb_state != LevelDbOnDiskState::kNone)
? DomStorageDatabase::GetLevelDbPath(
storage_type, storage_partition_dir)
: DomStorageDatabase::GetSqlitePath(
storage_type, storage_partition_dir);
Xiaohan Zhao . resolved

Question: in a normal rollout I think only one active backend should exist, but should we defensively clear both possible backend paths in case a partial clean up leaves both LevelDB and SQLite on disk? Is that possible?

Rahul Singh

Good question! Steve and I previously discussed this. IIRC we settled on this is worth a TODO but not an OnDisk Experiment blocker. @ste...@microsoft.com does that sound accurate?

Steve Becker

For this experiment, I think we should only delete one type of database. This is a good question for our future database migration. To keep things simple, I don't think we should consider the migration successful unless we've deleted the levelDB after migrating to sqlite.

Rahul Singh

Thanks Steve! I've added a short TODO in code for now.

File components/services/storage/dom_storage/local_storage_impl_unittest.cc
Line 1635, Patchset 14: GetParam() ? DomStorageSqliteRolloutStage::kUseSqliteForNewDatabases
: DomStorageSqliteRolloutStage::kUseLevelDbAsControl;
Steve Becker . resolved

Do we have test coverage for kUseLevelDbOnly and kUseSqliteOnly?

Rahul Singh

Good catch. I extended the existing tests to cover the other 2 param states too. Thanks!

File components/services/storage/dom_storage/session_storage_impl.cc
Line 700, Patchset 5: base::BindOnce(&SessionStorageImpl::OnDiskStateCleared,
Steve Becker . unresolved

We should try to avoid waiting for deletion if possible. It puts us into a weird state where database_ is nullptr while waiting for the delete to finish. Maybe we can add a flag to the proposed DomStorageDatabaseFactory::Open (see other comments) that will kick off the deletion before creating and opening the database.

Rahul Singh

Good idea! I’ll tackle this in a follow up CL as this one is already fairly large. I can chain it on top of this relation chain so we’ll have it before we start the Finch.

Open in Gerrit

Related details

Attention is currently required from:
  • Steve Becker
  • Xiaohan Zhao
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement is not satisfiedCode-Owners
  • requirement is not satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
Gerrit-Change-Number: 7877569
Gerrit-PatchSet: 15
Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-CC: James Maclean <wjma...@chromium.org>
Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-Attention: Steve Becker <ste...@microsoft.com>
Gerrit-Comment-Date: Thu, 18 Jun 2026 06:07:10 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Comment-In-Reply-To: Rahul Singh <rah...@microsoft.com>
Comment-In-Reply-To: Xiaohan Zhao <xiaoh...@microsoft.com>
Comment-In-Reply-To: Steve Becker <ste...@microsoft.com>
satisfied_requirement
unsatisfied_requirement
open
diffy

Steve Becker (Gerrit)

unread,
Jun 18, 2026, 4:02:02 PM (11 days ago) Jun 18
to Rahul Singh, Xiaohan Zhao, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
Attention needed from Rahul Singh and Xiaohan Zhao

Steve Becker voted and added 2 comments

Votes added by Steve Becker

Code-Review+1

2 comments

File components/services/storage/dom_storage/async_dom_storage_database.cc
Line 263, Patchset 15 (Latest): if (is_database_opened_) {
CHECK(database_);
}
Steve Becker . unresolved

nit: simplify:

CHECK_EQ(is_database_opened_, database_)

File components/services/storage/dom_storage/dom_storage_database.cc
Line 219, Patchset 15 (Latest): return std::move(*base::WrapUnique(database_ptr));
Steve Becker . unresolved

nit: don't need std::move for the return value. It's implicit.

Open in Gerrit

Related details

Attention is currently required from:
  • Rahul Singh
  • Xiaohan Zhao
Submit Requirements:
  • requirement satisfiedCode-Coverage
  • requirement satisfiedCode-Owners
  • requirement satisfiedCode-Review
  • requirement is not satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: chromium/src
Gerrit-Branch: main
Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
Gerrit-Change-Number: 7877569
Gerrit-PatchSet: 15
Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-CC: James Maclean <wjma...@chromium.org>
Gerrit-Attention: Rahul Singh <rah...@microsoft.com>
Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
Gerrit-Comment-Date: Thu, 18 Jun 2026 20:01:46 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
satisfied_requirement
unsatisfied_requirement
open
diffy

Rahul Singh (Gerrit)

unread,
Jun 19, 2026, 12:50:17 AM (11 days ago) Jun 19
to Steve Becker, Xiaohan Zhao, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
Attention needed from Xiaohan Zhao

Rahul Singh voted and added 2 comments

Votes added by Rahul Singh

Code-Review+1
Commit-Queue+2

2 comments

File components/services/storage/dom_storage/async_dom_storage_database.cc
Line 263, Patchset 15: if (is_database_opened_) {
CHECK(database_);
}
Steve Becker . resolved

nit: simplify:

CHECK_EQ(is_database_opened_, database_)

Rahul Singh

SequenceBound only has an explicit operator bool() (its null check), and CHECK_EQ expands to ==, which requires an implicit bool conversion. So, CHECK_EQ(is_database_opened_, database_) won't compile.

We also can't do CHECK_EQ(!database_.is_null(), is_database_opened) because we still return a database_ when Open fails. So we will trigger the CHECK in cases where Open fails.

As such, I think we should leave this as is.

File components/services/storage/dom_storage/dom_storage_database.cc
Line 219, Patchset 15: return std::move(*base::WrapUnique(database_ptr));
Steve Becker . resolved

nit: don't need std::move for the return value. It's implicit.

Rahul Singh

Dereferencing the unique_ptr will return an lvalue reference. The compiler tries to copy it on return. But SequenceBound has a deleted copy constructor. So this doesn't compile without the std::move.

Open in Gerrit

Related details

Attention is currently required from:
  • Xiaohan Zhao
Submit Requirements:
    • requirement satisfiedCode-Coverage
    • requirement satisfiedCode-Owners
    • requirement satisfiedCode-Review
    • requirement is not satisfiedNo-Unresolved-Comments
    • requirement satisfiedReview-Enforcement
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: chromium/src
    Gerrit-Branch: main
    Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
    Gerrit-Change-Number: 7877569
    Gerrit-PatchSet: 16
    Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
    Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
    Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
    Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
    Gerrit-CC: James Maclean <wjma...@chromium.org>
    Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
    Gerrit-Comment-Date: Fri, 19 Jun 2026 04:49:37 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: Yes
    Comment-In-Reply-To: Steve Becker <ste...@microsoft.com>
    satisfied_requirement
    unsatisfied_requirement
    open
    diffy

    Rahul Singh (Gerrit)

    unread,
    Jun 19, 2026, 1:10:37 AM (11 days ago) Jun 19
    to Steve Becker, Xiaohan Zhao, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
    Attention needed from Xiaohan Zhao

    Rahul Singh voted and added 1 comment

    Votes added by Rahul Singh

    Code-Review+1
    Commit-Queue+2

    1 comment

    File components/services/storage/dom_storage/session_storage_impl.cc
    Line 700, Patchset 5: base::BindOnce(&SessionStorageImpl::OnDiskStateCleared,
    Steve Becker . resolved

    We should try to avoid waiting for deletion if possible. It puts us into a weird state where database_ is nullptr while waiting for the delete to finish. Maybe we can add a flag to the proposed DomStorageDatabaseFactory::Open (see other comments) that will kick off the deletion before creating and opening the database.

    Rahul Singh

    Good idea! I’ll tackle this in a follow up CL as this one is already fairly large. I can chain it on top of this relation chain so we’ll have it before we start the Finch.

    Rahul Singh

    Here's the follow up CL that will tackle this. I'll open it up for review within the next day.

    7966139: DomStorage: Fold DomStorageDatabase Destroy into Open | https://chromium-review.googlesource.com/c/chromium/src/+/7966139

    Open in Gerrit

    Related details

    Attention is currently required from:
    • Xiaohan Zhao
    Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
      Gerrit-Change-Number: 7877569
      Gerrit-PatchSet: 17
      Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
      Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
      Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
      Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
      Gerrit-CC: James Maclean <wjma...@chromium.org>
      Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
      Gerrit-Comment-Date: Fri, 19 Jun 2026 05:10:14 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: Yes
      Comment-In-Reply-To: Rahul Singh <rah...@microsoft.com>
      Comment-In-Reply-To: Steve Becker <ste...@microsoft.com>
      satisfied_requirement
      open
      diffy

      Rahul Singh (Gerrit)

      unread,
      Jun 19, 2026, 4:32:57 PM (10 days ago) Jun 19
      to Steve Becker, Xiaohan Zhao, James Maclean, android-bu...@system.gserviceaccount.com, Chromium LUCI CQ, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org
      Attention needed from Xiaohan Zhao

      Rahul Singh voted Commit-Queue+2

      Commit-Queue+2
      Open in Gerrit

      Related details

      Attention is currently required from:
      • Xiaohan Zhao
      Submit Requirements:
      • requirement satisfiedCode-Coverage
      • requirement satisfiedCode-Owners
      • requirement satisfiedCode-Review
      • requirement satisfiedReview-Enforcement
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
      Gerrit-Change-Number: 7877569
      Gerrit-PatchSet: 18
      Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
      Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
      Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
      Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
      Gerrit-CC: James Maclean <wjma...@chromium.org>
      Gerrit-Attention: Xiaohan Zhao <xiaoh...@microsoft.com>
      Gerrit-Comment-Date: Fri, 19 Jun 2026 20:32:42 +0000
      Gerrit-HasComments: No
      Gerrit-Has-Labels: Yes
      satisfied_requirement
      open
      diffy

      Chromium LUCI CQ (Gerrit)

      unread,
      Jun 19, 2026, 4:54:38 PM (10 days ago) Jun 19
      to Rahul Singh, Steve Becker, Xiaohan Zhao, James Maclean, android-bu...@system.gserviceaccount.com, chromium...@chromium.org, dmurph+watching...@chromium.org, dmurph+watch...@chromium.org, edgesto...@microsoft.com, storage...@chromium.org

      Chromium LUCI CQ submitted the change with unreviewed changes

      Unreviewed changes

      17 is the latest approved patch-set.
      The change was submitted with unreviewed changes in the following files:

      ```
      The name of the file: components/services/storage/dom_storage/dom_storage_database.cc
      Insertions: 17, Deletions: 18.

      @@ -4,7 +4,6 @@

      #include "components/services/storage/dom_storage/dom_storage_database.h"

      -#include "base/debug/leak_annotations.h"
      #include "base/feature_list.h"
      #include "base/functional/bind.h"
      #include "base/memory/ptr_util.h"
      @@ -194,29 +193,29 @@
      scoped_refptr<base::SequencedTaskRunner> task_runner,
      std::unique_ptr<DomStorageDatabase> database) {
      CHECK(!database_);
      - // Binds `database` to `task_runner`, then heap-allocates and deliberately
      - // leaks the `SequenceBound` so ownership can cross to the caller's sequence
      - // as a raw pointer, to be re-owned by `TakeDatabase()`. Leaking matters
      - // because the reply may be dropped after shutdown; destroying an owned
      - // `SequenceBound` then would post a shutdown-blocking task to delete the
      - // database and DCHECK, whereas a dropped raw pointer simply leaks. See
      + // Hold the database with a deleter that destroys it on `task_runner` (its
      + // backend sequence) if this result is dropped before `TakeDatabase()` (e.g.
      + // the open reply is dropped because its owner was torn down). Without this we
      + // leak the opened database, which keeps its file handle open and prevents
      + // Windows from deleting TempDirs created during test runs.
      + //
      + // Unlike a `SequenceBound`, a `std::unique_ptr` with an `OnTaskRunnerDeleter`
      + // relies on `DeleteSoon`, which closes the database's file handle on drop
      + // while fizzling the destruction if posted after thread pool shutdown. See
      // https://crbug.com/40746642.
      - auto holder = std::make_unique<
      - base::SequenceBound<std::unique_ptr<DomStorageDatabase>>>(
      - std::move(task_runner), std::move(database));
      - auto* database_ptr = holder.release();
      - ANNOTATE_LEAKING_OBJECT_PTR(database_ptr);
      - database_ = database_ptr;
      + database_ = std::unique_ptr<DomStorageDatabase, base::OnTaskRunnerDeleter>(
      + database.release(), base::OnTaskRunnerDeleter(std::move(task_runner)));

      }

      base::SequenceBound<std::unique_ptr<DomStorageDatabase>>
       DomStorageDatabaseFactory::OpenResult::TakeDatabase() {
      CHECK(database_);
      - // Re-own the leaked `SequenceBound` and clear the raw pointer so it doesn't
      - // dangle.
      - auto* database_ptr = database_.get();
      - database_ = nullptr;
      - return std::move(*base::WrapUnique(database_ptr));
      + // Re-bind the opened database to its backend sequence for the caller.
      + // Adopting the pointer does not touch the database off-sequence.
      + scoped_refptr<base::SequencedTaskRunner> task_runner =
      + database_.get_deleter().task_runner_;
      + return base::SequenceBound<std::unique_ptr<DomStorageDatabase>>(
      + std::move(task_runner), base::WrapUnique(database_.release()));
      }

      // static
      ```
      ```
      The name of the file: components/services/storage/dom_storage/dom_storage_database.h
      Insertions: 12, Deletions: 10.

      @@ -17,7 +17,6 @@
      #include "base/byte_size.h"
      #include "base/containers/span.h"
      #include "base/functional/callback.h"
      -#include "base/memory/raw_ptr.h"
      #include "base/memory/ref_counted.h"
      #include "base/memory/scoped_refptr.h"
      #include "base/task/sequenced_task_runner.h"
      @@ -374,14 +373,15 @@
      OpenResult(OpenResult&&);
      OpenResult& operator=(OpenResult&&);

      - // Binds `database` to `task_runner` and stores it for transport to the
      - // caller's sequence. Producers of an `OpenResult` must set the database via
      - // this. See the definition for why the stored pointer is leaked.
      + // Stores `database` for transport to the caller's sequence, with a deleter
      + // that destroys it on `task_runner` (its backend sequence) if the result is
      + // dropped before `TakeDatabase()`. Producers of an `OpenResult` must set
      + // the database via this.
      void SetDatabase(scoped_refptr<base::SequencedTaskRunner> task_runner,
      std::unique_ptr<DomStorageDatabase> database);

      - // Re-owns and returns the database previously stored by `SetDatabase()`.
      - // Must be called once, on the caller's sequence.
      + // Returns the database stored by `SetDatabase()`, bound to its backend
      + // sequence. Must be called once, on the caller's sequence.
      base::SequenceBound<std::unique_ptr<DomStorageDatabase>> TakeDatabase();

      base::FilePath database_path;
      @@ -390,10 +390,12 @@
      DbStatus open_status = DbStatus::IOError("uninitialized");

      private:
      - // Leaked, non-owning pointer to the opened database while the result is in
      - // flight to the caller's sequence. See `SetDatabase()`.
      - raw_ptr<base::SequenceBound<std::unique_ptr<DomStorageDatabase>>>
      - database_ = nullptr;
      + // The opened database while the result is in flight to the caller's
      + // sequence. If the result is dropped before `TakeDatabase()`, the
      + // `OnTaskRunnerDeleter` destroys it on its backend sequence, closing its
      + // file handle.
      + std::unique_ptr<DomStorageDatabase, base::OnTaskRunnerDeleter> database_{
      + nullptr, base::OnTaskRunnerDeleter(nullptr)};
      };

      using OpenResultCallback = base::OnceCallback<void(OpenResult)>;
      ```

      Change information

      Commit message:
      DomStorage: Make DomStorageDatabaseFactory async and rollout-aware

      Converts `DomStorageDatabaseFactory::Open` and `Destroy` to asynchronous
      APIs that take a `storage_partition_dir` plus a callback, and moves the
      rollout decision into the factory. For on-disk databases in an
      experimental stage, both methods post a blocking task to inspect the
      on-disk state (existing LevelDB directory and exp-v1 tag) and use it to
      pick the backend, database path, `write_exp_tag` value, and histogram
      metrics_type.

      `Open` opens the database and returns its related state via a new
      `OpenResult` struct, which `AsyncDomStorageDatabase::OnDatabaseOpened`
      consumes to take the opened database and record metrics with
      `GetHistogramSuffix(metrics_type_)`. Callers (`LocalStorageImpl`,
      `SessionStorageImpl`, their tests, and `FakeDomStorageDatabaseFactory`)
      are updated to the new signatures, and the now-redundant
      `GetDatabasePath()` helpers are removed.
      Bug: 377242771
      Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
      Commit-Queue: Rahul Singh <rah...@microsoft.com>
      Reviewed-by: Steve Becker <ste...@microsoft.com>
      Reviewed-by: Rahul Singh <rah...@microsoft.com>
      Cr-Commit-Position: refs/heads/main@{#1649800}
      Files:
      • M components/services/storage/dom_storage/async_dom_storage_database.cc
      • M components/services/storage/dom_storage/async_dom_storage_database.h
      • M components/services/storage/dom_storage/dom_storage_database.cc
      • M components/services/storage/dom_storage/dom_storage_database.h
      • M components/services/storage/dom_storage/dom_storage_database_unittest.cc
      • M components/services/storage/dom_storage/leveldb/local_storage_leveldb.cc
      • M components/services/storage/dom_storage/leveldb/local_storage_leveldb.h
      • M components/services/storage/dom_storage/leveldb/local_storage_leveldb_unittest.cc
      • M components/services/storage/dom_storage/leveldb/session_storage_leveldb.cc
      • M components/services/storage/dom_storage/leveldb/session_storage_leveldb.h
      • M components/services/storage/dom_storage/leveldb/session_storage_leveldb_unittest.cc
      • M components/services/storage/dom_storage/local_storage_impl.cc
      • M components/services/storage/dom_storage/local_storage_impl.h
      • M components/services/storage/dom_storage/local_storage_impl_unittest.cc
      • M components/services/storage/dom_storage/session_storage_impl.cc
      • M components/services/storage/dom_storage/session_storage_impl.h
      • M components/services/storage/dom_storage/session_storage_impl_unittest.cc
      • M components/services/storage/dom_storage/sqlite/local_storage_sqlite.h
      • M components/services/storage/dom_storage/sqlite/session_storage_sqlite.h
      • M components/services/storage/dom_storage/test_support/fake_dom_storage_database.h
      • M components/services/storage/dom_storage/test_support/fake_dom_storage_database_factory.cc
      • M components/services/storage/dom_storage/test_support/fake_dom_storage_database_factory.h
      • M components/services/storage/dom_storage/test_support/scoped_dom_storage_database_factory_for_testing.cc
      • M components/services/storage/dom_storage/test_support/scoped_dom_storage_database_factory_for_testing.h
      • M content/browser/dom_storage/dom_storage_context_wrapper.cc
      • M content/browser/storage_partition_impl_unittest.cc
      Change size: XL
      Delta: 26 files changed, 1061 insertions(+), 295 deletions(-)
      Branch: refs/heads/main
      Submit Requirements:
      • requirement satisfiedCode-Review: +1 by Rahul Singh, +1 by Steve Becker
      Open in Gerrit
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: merged
      Gerrit-Project: chromium/src
      Gerrit-Branch: main
      Gerrit-Change-Id: Ia31ca9efd136f08a832fbb5e41bbe436b34c8242
      Gerrit-Change-Number: 7877569
      Gerrit-PatchSet: 19
      Gerrit-Owner: Rahul Singh <rah...@microsoft.com>
      Gerrit-Reviewer: Chromium LUCI CQ <chromiu...@luci-project-accounts.iam.gserviceaccount.com>
      Gerrit-Reviewer: Rahul Singh <rah...@microsoft.com>
      Gerrit-Reviewer: Steve Becker <ste...@microsoft.com>
      Gerrit-Reviewer: Xiaohan Zhao <xiaoh...@microsoft.com>
      open
      diffy
      satisfied_requirement
      Reply all
      Reply to author
      Forward
      0 new messages