just playing with tangled
at gvimdiff 103 lines 3.9 kB view raw
1// Copyright 2020 The Jujutsu Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15use std::cmp::max; 16use std::sync::Arc; 17use std::thread; 18 19use jj_lib::dag_walk; 20use jj_lib::repo::ReadonlyRepo; 21use jj_lib::repo::Repo as _; 22use test_case::test_case; 23use testutils::write_random_commit; 24use testutils::TestRepoBackend; 25use testutils::TestWorkspace; 26 27fn count_non_merge_operations(repo: &Arc<ReadonlyRepo>) -> usize { 28 let op_store = repo.op_store(); 29 let op_id = repo.op_id().clone(); 30 let mut num_ops = 0; 31 32 for op_id in dag_walk::dfs( 33 vec![op_id], 34 |op_id| op_id.clone(), 35 |op_id| op_store.read_operation(op_id).unwrap().parents, 36 ) { 37 if op_store.read_operation(&op_id).unwrap().parents.len() <= 1 { 38 num_ops += 1; 39 } 40 } 41 num_ops 42} 43 44#[test_case(TestRepoBackend::Simple ; "simple backend")] 45#[test_case(TestRepoBackend::Git ; "git backend")] 46fn test_commit_parallel(backend: TestRepoBackend) { 47 // This loads a Repo instance and creates and commits many concurrent 48 // transactions from it. It then reloads the repo. That should merge all the 49 // operations and all commits should be visible. 50 let test_workspace = TestWorkspace::init_with_backend(backend); 51 let repo = &test_workspace.repo; 52 53 let num_threads = max(num_cpus::get(), 4); 54 thread::scope(|s| { 55 for _ in 0..num_threads { 56 let repo = repo.clone(); 57 s.spawn(move || { 58 let mut tx = repo.start_transaction(); 59 write_random_commit(tx.repo_mut()); 60 tx.commit("test").unwrap(); 61 }); 62 } 63 }); 64 let repo = repo.reload_at_head().unwrap(); 65 // One commit per thread plus the commit from the initial working-copy on top of 66 // the root commit 67 assert_eq!(repo.view().heads().len(), num_threads + 1); 68 69 // One additional operation for the root operation, one for checking out the 70 // initial commit. 71 assert_eq!(count_non_merge_operations(&repo), num_threads + 2); 72} 73 74#[test_case(TestRepoBackend::Simple ; "simple backend")] 75#[test_case(TestRepoBackend::Git ; "git backend")] 76fn test_commit_parallel_instances(backend: TestRepoBackend) { 77 // Like the test above but creates a new repo instance for every thread, which 78 // makes it behave very similar to separate processes. 79 let settings = testutils::user_settings(); 80 let test_workspace = TestWorkspace::init_with_backend_and_settings(backend, &settings); 81 let test_env = &test_workspace.env; 82 83 let num_threads = max(num_cpus::get(), 4); 84 thread::scope(|s| { 85 for _ in 0..num_threads { 86 let settings = settings.clone(); 87 let repo = test_env.load_repo_at_head(&settings, test_workspace.repo_path()); 88 s.spawn(move || { 89 let mut tx = repo.start_transaction(); 90 write_random_commit(tx.repo_mut()); 91 tx.commit("test").unwrap(); 92 }); 93 } 94 }); 95 // One commit per thread plus the commit from the initial working-copy commit on 96 // top of the root commit 97 let repo = test_env.load_repo_at_head(&settings, test_workspace.repo_path()); 98 assert_eq!(repo.view().heads().len(), num_threads + 1); 99 100 // One additional operation for the root operation, one for checking out the 101 // initial commit. 102 assert_eq!(count_non_merge_operations(&repo), num_threads + 2); 103}