mirror of
https://github.com/servo/servo
synced 2026-04-25 17:15:48 +02:00
storage: Add support for temporary storage (#44433)
Add support for temporary storage via a new config option `temporary_storage` and a corresponding command-line argument `--temporary-storage`. When enabled, client storage uses a storage directory (e.g. `clientstorage/temporary/<uuid>`) instead of the shared default location. This can be used to provide isolation between concurrent servo instances. This is especially useful for WPT runs, where multiple Servo instances may execute in parallel and would otherwise share the same storage, leading to cross-test interference. Based on that, this PR also updates the WPT runner to enable temporary storage by default. Testing: Manual testing and a full try run. Signed-off-by: Jan Varga <jvarga@igalia.com>
This commit is contained in:
@@ -60,6 +60,9 @@ pub struct Opts {
|
||||
/// Directory for a default config directory
|
||||
pub config_dir: Option<PathBuf>,
|
||||
|
||||
/// Use temporary storage (data on disk will not persist across restarts).
|
||||
pub temporary_storage: bool,
|
||||
|
||||
/// Path to PEM encoded SSL CA certificate store.
|
||||
pub certificate_path: Option<String>,
|
||||
|
||||
@@ -222,6 +225,7 @@ impl Default for Opts {
|
||||
sandbox: false,
|
||||
debug: Default::default(),
|
||||
config_dir: None,
|
||||
temporary_storage: false,
|
||||
shaders_path: None,
|
||||
certificate_path: None,
|
||||
ignore_certificate_errors: false,
|
||||
|
||||
@@ -930,8 +930,11 @@ impl Servo {
|
||||
protocols.clone(),
|
||||
);
|
||||
|
||||
let (private_storage_threads, public_storage_threads) =
|
||||
new_storage_threads(mem_profiler_chan.clone(), opts.config_dir.clone());
|
||||
let (private_storage_threads, public_storage_threads) = new_storage_threads(
|
||||
mem_profiler_chan.clone(),
|
||||
opts.config_dir.clone(),
|
||||
opts.temporary_storage,
|
||||
);
|
||||
|
||||
create_constellation(
|
||||
embedder_to_constellation_receiver,
|
||||
|
||||
@@ -642,19 +642,25 @@ impl RegistryEngine for SqliteEngine {
|
||||
}
|
||||
|
||||
pub trait ClientStorageThreadFactory {
|
||||
fn new(config_dir: Option<PathBuf>) -> Self;
|
||||
fn new(config_dir: Option<PathBuf>, temporary_storage: bool) -> Self;
|
||||
}
|
||||
|
||||
impl ClientStorageThreadFactory for ClientStorageThreadHandle {
|
||||
fn new(config_dir: Option<PathBuf>) -> ClientStorageThreadHandle {
|
||||
fn new(config_dir: Option<PathBuf>, temporary_storage: bool) -> ClientStorageThreadHandle {
|
||||
let (generic_sender, generic_receiver) = generic_channel::channel().unwrap();
|
||||
|
||||
let storage_dir = config_dir
|
||||
let base_dir = config_dir
|
||||
.unwrap_or_else(|| {
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
tmp_dir.path().to_path_buf()
|
||||
})
|
||||
.join("clientstorage");
|
||||
let storage_dir = if temporary_storage {
|
||||
let unique_id = uuid::Uuid::new_v4().to_string();
|
||||
base_dir.join("temporary").join(unique_id)
|
||||
} else {
|
||||
base_dir.join("default_v1")
|
||||
};
|
||||
std::fs::create_dir_all(&storage_dir)
|
||||
.expect("Failed to create ClientStorage storage directory");
|
||||
let sender_clone = generic_sender.clone();
|
||||
|
||||
@@ -16,10 +16,11 @@ use crate::{ClientStorageThreadFactory, IndexedDBThreadFactory, WebStorageThread
|
||||
fn new_storage_thread_group(
|
||||
mem_profiler_chan: MemProfilerChan,
|
||||
config_dir: Option<PathBuf>,
|
||||
temporary_storage: bool,
|
||||
label: &str,
|
||||
) -> StorageThreads {
|
||||
let client_storage: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(config_dir.clone());
|
||||
ClientStorageThreadFactory::new(config_dir.clone(), temporary_storage);
|
||||
let idb: GenericSender<IndexedDBThreadMsg> = IndexedDBThreadFactory::new(
|
||||
config_dir.clone(),
|
||||
mem_profiler_chan.clone(),
|
||||
@@ -37,10 +38,16 @@ fn new_storage_thread_group(
|
||||
pub fn new_storage_threads(
|
||||
mem_profiler_chan: MemProfilerChan,
|
||||
config_dir: Option<PathBuf>,
|
||||
temporary_storage: bool,
|
||||
) -> (StorageThreads, StorageThreads) {
|
||||
let private_storage_threads =
|
||||
new_storage_thread_group(mem_profiler_chan.clone(), config_dir.clone(), "private");
|
||||
let public_storage_threads = new_storage_thread_group(mem_profiler_chan, config_dir, "public");
|
||||
let private_storage_threads = new_storage_thread_group(
|
||||
mem_profiler_chan.clone(),
|
||||
config_dir.clone(),
|
||||
temporary_storage,
|
||||
"private",
|
||||
);
|
||||
let public_storage_threads =
|
||||
new_storage_thread_group(mem_profiler_chan, config_dir, temporary_storage, "public");
|
||||
|
||||
(private_storage_threads, public_storage_threads)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@ fn install_test_namespace() {
|
||||
}
|
||||
|
||||
fn registry_db_path(tmp_dir: &tempfile::TempDir) -> PathBuf {
|
||||
tmp_dir.path().join("clientstorage").join("reg.sqlite")
|
||||
tmp_dir
|
||||
.path()
|
||||
.join("clientstorage")
|
||||
.join("default_v1")
|
||||
.join("reg.sqlite")
|
||||
}
|
||||
|
||||
fn open_registry(tmp_dir: &tempfile::TempDir) -> Connection {
|
||||
@@ -42,7 +46,7 @@ fn obtain_bottle_map(
|
||||
|
||||
#[test]
|
||||
fn test_exit() {
|
||||
let handle: ClientStorageThreadHandle = ClientStorageThreadFactory::new(None);
|
||||
let handle: ClientStorageThreadHandle = ClientStorageThreadFactory::new(None, false);
|
||||
|
||||
let (sender, receiver) = generic_channel::channel().unwrap();
|
||||
handle
|
||||
@@ -60,7 +64,7 @@ fn test_workflow() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let url = ServoUrl::parse("https://example.com").unwrap();
|
||||
|
||||
@@ -124,7 +128,7 @@ fn test_repeated_local_obtain_reuses_same_logical_rows() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("https://example.com").unwrap().origin();
|
||||
let webview = WebViewId::new(servo_base::id::TEST_PAINTER_ID);
|
||||
@@ -179,7 +183,7 @@ fn test_repeated_session_obtain_reuses_same_logical_rows() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("https://example.com").unwrap().origin();
|
||||
let webview = WebViewId::new(servo_base::id::TEST_PAINTER_ID);
|
||||
@@ -235,7 +239,7 @@ fn test_local_persistence_and_estimate() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("https://example.com").unwrap().origin();
|
||||
let webview = WebViewId::new(servo_base::id::TEST_PAINTER_ID);
|
||||
@@ -287,7 +291,7 @@ fn test_storage_manager_operations_fail_for_opaque_origins() {
|
||||
install_test_namespace();
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let handle: ClientStorageThreadHandle =
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()));
|
||||
ClientStorageThreadFactory::new(Some(tmp_dir.path().to_path_buf()), false);
|
||||
|
||||
let origin = ServoUrl::parse("data:text/plain,hello").unwrap().origin();
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ fn shutdown_storage_group(threads: &StorageThreads) {
|
||||
fn test_new_storage_threads_create_independent_groups() {
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let (private_storage_threads, public_storage_threads) =
|
||||
storage::new_storage_threads(mem_profiler_chan, None);
|
||||
storage::new_storage_threads(mem_profiler_chan, None, false);
|
||||
|
||||
shutdown_storage_group(&private_storage_threads);
|
||||
shutdown_storage_group(&public_storage_threads);
|
||||
|
||||
@@ -22,7 +22,7 @@ impl WebStorageTest {
|
||||
let tmp_dir = tempfile::tempdir().unwrap();
|
||||
let config_dir = tmp_dir.path().to_path_buf();
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, Some(config_dir));
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, Some(config_dir), false);
|
||||
|
||||
Self {
|
||||
tmp_dir: Some(tmp_dir),
|
||||
@@ -32,7 +32,7 @@ impl WebStorageTest {
|
||||
|
||||
pub(crate) fn new_in_memory() -> Self {
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, None);
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, None, false);
|
||||
|
||||
Self {
|
||||
tmp_dir: None,
|
||||
@@ -44,7 +44,7 @@ impl WebStorageTest {
|
||||
let tmp_dir = self.tmp_dir.take();
|
||||
let config_dir = tmp_dir.as_ref().map(|d| d.path().to_path_buf());
|
||||
let mem_profiler_chan = profile_mem::Profiler::create();
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, config_dir);
|
||||
let threads = storage::new_storage_threads(mem_profiler_chan, config_dir, false);
|
||||
|
||||
Self {
|
||||
tmp_dir: tmp_dir,
|
||||
|
||||
@@ -378,6 +378,10 @@ struct CmdArgs {
|
||||
#[bpaf(argument("~/.config/servo"))]
|
||||
config_dir: Option<PathBuf>,
|
||||
|
||||
/// Use temporary storage (data on disk will not persist across restarts).
|
||||
#[bpaf(long)]
|
||||
temporary_storage: bool,
|
||||
|
||||
///
|
||||
/// Run as a content process and connect to the given pipe.
|
||||
#[bpaf(argument("servo-ipc-channel.abcdefg"))]
|
||||
@@ -634,6 +638,7 @@ fn parse_arguments_helper(args_without_binary: Args) -> ArgumentParsingResult {
|
||||
fs::create_dir_all(config_dir).expect("Could not create config_dir");
|
||||
}
|
||||
});
|
||||
let temporary_storage = cmd_args.temporary_storage;
|
||||
if let Some(ref time_profiler_trace_path) = cmd_args.profiler_trace_path {
|
||||
let mut path = PathBuf::from(time_profiler_trace_path);
|
||||
path.pop();
|
||||
@@ -706,6 +711,7 @@ fn parse_arguments_helper(args_without_binary: Args) -> ArgumentParsingResult {
|
||||
random_pipeline_closure_probability: cmd_args.random_pipeline_closure_probability,
|
||||
random_pipeline_closure_seed: cmd_args.random_pipeline_closure_seed,
|
||||
config_dir,
|
||||
temporary_storage,
|
||||
shaders_path: cmd_args.shaders,
|
||||
certificate_path: cmd_args
|
||||
.certificate_path
|
||||
|
||||
@@ -136,6 +136,9 @@ def run_tests(default_binary_path: str, multiprocess: bool, **kwargs: Any) -> in
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="servo-") as config_dir:
|
||||
kwargs["binary_args"] += ["--config-dir", config_dir]
|
||||
# Temporary workaround to avoid shared storage across parallel processes.
|
||||
# Can be removed once per-process config dirs are supported.
|
||||
kwargs["binary_args"] += ["--temporary-storage"]
|
||||
|
||||
wptrunner.run_tests(**kwargs)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user