Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions docs/architecture/indexeddb-persistence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Persistent IndexedDB compatibility

WebScene's native V8 runtime can expose a durable IndexedDB subset for packaged
applications such as VS Code OSS. The host opts in with two values:

- `PersistentStorageDirectory`: a private directory owned by the host;
- `PersistentStoragePartitionKey`: a stable application/profile identifier.

`PersistentStorageQuotaBytes` sets the whole-partition quota. Zero selects the
native default of 256 MiB. IndexedDB remains absent when either required value is
empty, so an application never receives an in-memory API presented as durable.
The component manifest must also declare `storage.indexeddb` for SDK preflight.

The partition key separates applications and profiles. The runtime adds the
document origin and database name below it. Loopback origins use a stable
`scheme//loopback` identity so a trusted host can restart on a different ephemeral
port without losing `vscode-web-state-db-global`, `vscode-web-state-db-global-shared`,
or `vscode-web-state-db-empty-window`. Non-loopback origins retain their full origin.

## Commit and recovery model

Each database is one revisioned snapshot produced by V8 structured clone. Disk I/O
runs on a dedicated storage thread; the V8 owner thread only serializes/deserializes
and settles promises. A commit:

1. acquires a per-database interprocess directory lock;
2. reloads and validates the current revision;
3. rejects a stale expected revision;
4. checks the partition quota;
5. writes a temporary file with schema, identity, length, and content hash;
6. flushes the file and atomically replaces the prior revision.

Readers reject truncated, trailing, identity-mismatched, or hash-mismatched files
with `DataError`. The previous snapshot remains intact if a transaction aborts, a
quota check fails, or a stale writer loses a race. Read/write transactions replay
their mutation list against the latest same-version snapshot after a revision
conflict, up to four attempts. Version upgrades do not replay.

Hosts should remove a partition directory only while its engines are stopped.
Applications can remove an individual database with `indexedDB.deleteDatabase()`.

## Supported application surface

The current slice implements the operations used by VS Code OSS browser storage:

- `indexedDB.open`, `deleteDatabase`, `cmp`, and `databases` for databases seen by
the current realm;
- upgrade, blocked, and versionchange lifecycles;
- readonly, readwrite, and versionchange transactions with commit and abort;
- out-of-line string, finite number, Date, binary, and array keys;
- object store `get`, `put`, `add`, `delete`, `clear`, `count`, `getAll`,
`getAllKeys`, and forward cursors;
- structured objects, arrays, maps, sets, dates, array buffers, and typed arrays.

Indexes, `IDBKeyRange`, key paths, key generators, cursor update/delete and reverse
cursors are not yet implemented. Object stores requesting `keyPath` or
`autoIncrement`, and all index operations, fail with `NotSupportedError`. Blob/File
prototype restoration is not yet guaranteed across a durable round trip. This is a
bounded compatibility implementation and does not claim full IndexedDB WPT
conformance.

## Gates

`webscene_indexeddb_storage_tests` covers revision isolation, profile/origin
partitioning, rollback preservation, quota, corruption detection, asynchronous I/O,
abandoned temporary-write and stale-lock recovery, real cross-process stale-writer
rejection, and 100 durable 4 KiB commits under ten seconds.
`webscene_native_indexeddb_contract` covers the V8 API, Code OSS ItemTable
shape, upgrade/versionchange, rollback, cursors, restart across loopback port changes,
quota errors, and corruption errors.
The same regression deletes the rejected corrupt database and verifies that a
fresh version-one database can be created in its place.

The manifest names the native lifecycle regressions as evidence for candidate cases
that a single WPT document cannot drive: engine restart, direct file corruption,
process races, and interruption before atomic replacement. The runnable document
itself covers open/upgrade/versionchange, commit/rollback, cursors, request error
cancellation, connection reopen, quota, and competing connections.

The candidate manifest `tests/WebPlatformSubset/webscene-indexeddb-profile.json`
adds a project-owned WPT-style Code OSS transaction contract and records the focused
upstream areas that still require broader algorithms. Run it with a fresh directory:

```bash
dotnet run --project tests/WebPlatformSubset/runner -c Release -- \
--manifest tests/WebPlatformSubset/webscene-indexeddb-profile.json \
--selection candidate \
--native-library /absolute/path/to/libwebscene_native_engine.dylib \
--native-storage-directory /absolute/path/to/wpt-storage \
--native-storage-partition webscene-indexeddb-wpt \
--native-storage-quota-bytes 4194304 \
--output TestResults/WebPlatformSubset/indexeddb
```

Storage operations do not mutate DOM, style, layout, or retained-scene state. The
ordinary required visual profile remains the rendering regression gate when this
feature is promoted on each release RID.
17 changes: 16 additions & 1 deletion experiments/WebScene.NativeEngine.Probe/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ include(CTest)
include(FetchContent)

if(BUILD_TESTING)
add_executable(webscene_indexeddb_storage_tests
tests/indexeddb_storage_tests.cpp
native/webscene_indexeddb_storage.cpp)
target_compile_features(webscene_indexeddb_storage_tests PRIVATE cxx_std_20)
target_include_directories(webscene_indexeddb_storage_tests PRIVATE native)
add_test(NAME webscene_indexeddb_storage_tests
COMMAND webscene_indexeddb_storage_tests)
set_tests_properties(webscene_indexeddb_storage_tests PROPERTIES
LABELS "storage;durability;performance" TIMEOUT 20)
add_executable(webscene_graphics_scene_abi_layout_tests tests/graphics_scene_abi_layout_tests.c)
target_compile_features(webscene_graphics_scene_abi_layout_tests PRIVATE c_std_11)
target_include_directories(webscene_graphics_scene_abi_layout_tests PRIVATE native)
Expand All @@ -14,6 +23,7 @@ if(BUILD_TESTING)
target_include_directories(webscene_graphics_canvas_backing_tests PRIVATE native)
add_test(NAME webscene_graphics_canvas_backing_tests COMMAND webscene_graphics_canvas_backing_tests)
find_package(Threads REQUIRED)
target_link_libraries(webscene_indexeddb_storage_tests PRIVATE Threads::Threads)
add_executable(webscene_graphics_image_lease_tests tests/graphics_image_lease_tests.cpp)
target_compile_features(webscene_graphics_image_lease_tests PRIVATE cxx_std_20)
target_include_directories(webscene_graphics_image_lease_tests PRIVATE native)
Expand Down Expand Up @@ -79,7 +89,8 @@ else()
endif()
add_library(webscene_native_engine ${webscene_runtime_kind}
native/webscene_native_engine.cpp
native/webscene_secure_random.cpp)
native/webscene_secure_random.cpp
native/webscene_indexeddb_storage.cpp)
if(TARGET webscene_core)
target_link_libraries(webscene_native_engine PRIVATE webscene_core)
else()
Expand Down Expand Up @@ -783,6 +794,7 @@ if(WEBSCENE_NATIVE_ENGINE_ENABLE_V8)
COMMAND webscene_native_engine_tests)
add_test(NAME webscene_native_recursive_selector_cache
COMMAND webscene_native_engine_tests)
add_test(NAME webscene_native_indexeddb_contract COMMAND webscene_native_engine_tests)
set_tests_properties(webscene_native_idle_v8_platform PROPERTIES
ENVIRONMENT "WEBSCENE_NATIVE_ENGINE_TEST_FILTER=idle-v8-platform")
set_tests_properties(webscene_native_dom_punctuation_keyboard PROPERTIES
Expand All @@ -801,6 +813,9 @@ if(WEBSCENE_NATIVE_ENGINE_ENABLE_V8)
ENVIRONMENT "WEBSCENE_NATIVE_ENGINE_TEST_FILTER=recursive-selector-cache"
TIMEOUT 30
LABELS "native;runtime;performance")
set_tests_properties(webscene_native_indexeddb_contract PROPERTIES
ENVIRONMENT "WEBSCENE_NATIVE_ENGINE_TEST_FILTER=indexeddb"
LABELS "storage;indexeddb;durability" TIMEOUT 60)
set_tests_properties(webscene_native_engine_tests PROPERTIES
ENVIRONMENT
"WEBSCENE_V8_DETAILED_MEMORY_METRICS=1;WEBSCENE_INTEROP_STRESS=1")
Expand Down
Loading
Loading