From 389bb8e6feac38a1f04a34503f1f3d7ac8d62ff4 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 10 Nov 2023 11:42:47 +0900 Subject: [PATCH] Move static notes trees to Rust --- src/cinnabar-helper.c | 2 -- src/libcinnabar.rs | 47 ++++++++++++++++++++++++++----------------- src/libgit.rs | 34 +++++++++++++++++++++++++++++++ src/main.rs | 16 +++++++-------- src/store.rs | 34 +++++++++++++++---------------- 5 files changed, 88 insertions(+), 45 deletions(-) diff --git a/src/cinnabar-helper.c b/src/cinnabar-helper.c index 8cb025de2..a7de9ec7f 100644 --- a/src/cinnabar-helper.c +++ b/src/cinnabar-helper.c @@ -40,8 +40,6 @@ #include "cinnabar-fast-import.h" #include "cinnabar-notes.h" -struct notes_tree git2hg, hg2git, files_meta; - struct object_id *commit_oid(struct commit *c) { return &c->object.oid; } diff --git a/src/libcinnabar.rs b/src/libcinnabar.rs index bbf6faab9..7d2a4ad05 100644 --- a/src/libcinnabar.rs +++ b/src/libcinnabar.rs @@ -12,8 +12,8 @@ use std::ptr; use crate::git::{CommitId, GitObjectId, TreeId}; use crate::hg::HgObjectId; use crate::libgit::{ - child_process, die, object_id, strbuf, FileMode, RawTree, FILES_META_OID, GIT2HG_OID, - HG2GIT_OID, + child_process, die, notes_tree, object_id, strbuf, FileMode, RawTree, FILES_META_OID, + GIT2HG_OID, HG2GIT_OID, }; use crate::oid::{Abbrev, ObjectId}; use crate::store::{store_git_commit, MetadataFlags, METADATA_FLAGS}; @@ -98,15 +98,26 @@ impl From for HgObjectId { #[allow(non_camel_case_types)] #[repr(C)] pub struct cinnabar_notes_tree { - root: *mut c_void, - // ... + current: notes_tree, + additions: notes_tree, + init_flags: c_int, } -extern "C" { - pub static mut git2hg: git_notes_tree; - pub static mut hg2git: hg_notes_tree; - pub static mut files_meta: hg_notes_tree; +impl cinnabar_notes_tree { + const fn new() -> Self { + cinnabar_notes_tree { + current: notes_tree::new(), + additions: notes_tree::new(), + init_flags: 0, + } + } +} + +pub static mut GIT2HG: git_notes_tree = git_notes_tree(cinnabar_notes_tree::new()); +pub static mut HG2GIT: hg_notes_tree = hg_notes_tree(cinnabar_notes_tree::new()); +pub static mut FILES_META: hg_notes_tree = hg_notes_tree(cinnabar_notes_tree::new()); +extern "C" { fn combine_notes_ignore(cur_oid: *mut object_id, new_oid: *const object_id) -> c_int; fn cinnabar_init_notes( @@ -168,11 +179,11 @@ unsafe fn ensure_notes(t: *mut cinnabar_notes_tree) { if notes_initialized(t) == 0 { let oid; let mut flags = 0; - if ptr::eq(t, &git2hg.0) { + if ptr::eq(t, &GIT2HG.0) { oid = GIT2HG_OID; - } else if ptr::eq(t, &hg2git.0) { + } else if ptr::eq(t, &HG2GIT.0) { oid = HG2GIT_OID; - } else if ptr::eq(t, &files_meta.0) { + } else if ptr::eq(t, &FILES_META.0) { oid = FILES_META_OID; if !METADATA_FLAGS.contains(MetadataFlags::FILES_META) { flags = NOTES_INIT_EMPTY; @@ -210,8 +221,8 @@ fn for_each_note_in(notes: &mut cinnabar_not #[no_mangle] pub unsafe extern "C" fn resolve_hg2git(oid: *const hg_object_id) -> *const object_id { - ensure_notes(&mut hg2git.0); - get_note_hg(&mut hg2git.0, oid) + ensure_notes(&mut HG2GIT.0); + get_note_hg(&mut HG2GIT.0, oid) } unsafe fn get_note_hg( @@ -226,8 +237,8 @@ unsafe fn get_note_hg( #[no_mangle] pub unsafe extern "C" fn get_files_meta(oid: *const hg_object_id) -> *const object_id { - ensure_notes(&mut files_meta.0); - get_note_hg(&mut files_meta.0, oid) + ensure_notes(&mut FILES_META.0); + get_note_hg(&mut FILES_META.0, oid) } unsafe fn add_note_hg( @@ -244,7 +255,7 @@ unsafe fn add_note_hg( #[no_mangle] pub unsafe extern "C" fn add_hg2git(oid: *const hg_object_id, note_oid: *const object_id) -> c_int { - add_note_hg(&mut hg2git.0, oid, note_oid) + add_note_hg(&mut HG2GIT.0, oid, note_oid) } #[no_mangle] @@ -252,7 +263,7 @@ pub unsafe extern "C" fn add_files_meta( oid: *const hg_object_id, note_oid: *const object_id, ) -> c_int { - add_note_hg(&mut files_meta.0, oid, note_oid) + add_note_hg(&mut FILES_META.0, oid, note_oid) } pub unsafe fn store_metadata_notes( @@ -262,7 +273,7 @@ pub unsafe fn store_metadata_notes( let mut result = object_id::default(); let mut tree = object_id::default(); if notes_dirty(notes) != 0 { - let mode = if ptr::eq(notes, &hg2git.0) { + let mode = if ptr::eq(notes, &HG2GIT.0) { FileMode::GITLINK } else { FileMode::REGULAR | FileMode::RW diff --git a/src/libgit.rs b/src/libgit.rs index f4981c8a1..e5e7a2986 100644 --- a/src/libgit.rs +++ b/src/libgit.rs @@ -6,6 +6,7 @@ use std::ffi::{c_void, CStr, CString, OsStr, OsString}; use std::io::{self, Write}; use std::num::ParseIntError; use std::os::raw::{c_char, c_int, c_long, c_uint, c_ulong, c_ushort}; +use std::ptr; use std::str::FromStr; use std::sync::RwLock; use std::{fmt, mem}; @@ -1240,3 +1241,36 @@ pub fn reachable_subset( }, } } + +#[allow(non_camel_case_types)] +#[repr(C)] +pub struct notes_tree { + root: *mut c_void, + first_non_note: *mut c_void, + prev_non_note: *mut c_void, + r#ref: *const c_char, + update_ref: *const c_char, + combine_notes: + unsafe extern "C" fn(cur_oid: *mut object_id, new_oid: *const object_id) -> c_int, + initialized: c_int, + dirty: c_int, +} + +extern "C" { + fn combine_notes_ignore(cur_oid: *mut object_id, new_oid: *const object_id) -> c_int; +} + +impl notes_tree { + pub const fn new() -> Self { + notes_tree { + root: ptr::null_mut(), + first_non_note: ptr::null_mut(), + prev_non_note: ptr::null_mut(), + r#ref: ptr::null(), + update_ref: ptr::null(), + combine_notes: combine_notes_ignore, + initialized: 0, + dirty: 0, + } + } +} diff --git a/src/main.rs b/src/main.rs index c0b0ac637..e75e73722 100644 --- a/src/main.rs +++ b/src/main.rs @@ -106,7 +106,7 @@ use hg_connect::{get_bundle, get_clonebundle_url, get_connection, get_store_bund use indexmap::IndexSet; use itertools::EitherOrBoth::{Both, Left, Right}; use itertools::{EitherOrBoth, Itertools}; -use libcinnabar::{files_meta, git2hg, git_notes_tree, hg2git}; +use libcinnabar::{git_notes_tree, FILES_META, GIT2HG, HG2GIT}; use libgit::{ commit, config_get_value, die, diff_tree_with_copies, for_each_ref_in, for_each_remote, get_oid_committish, get_unique_abbrev, lookup_commit, lookup_replace_commit, object_id, @@ -290,7 +290,7 @@ pub fn prepare_arg(arg: OsString) -> Vec { fn do_one_hg2git(sha1: Abbrev) -> String { format!("{}", unsafe { - hg2git.get_note_abbrev(sha1).unwrap_or(GitObjectId::NULL) + HG2GIT.get_note_abbrev(sha1).unwrap_or(GitObjectId::NULL) }) } @@ -353,7 +353,7 @@ where fn do_data_changeset(rev: Abbrev) -> Result<(), String> { unsafe { - let commit_id = hg2git + let commit_id = HG2GIT .get_note_abbrev(rev) .ok_or_else(|| format!("Unknown changeset id: {}", rev))?; let changeset = RawHgChangeset::read(GitChangesetId::from_unchecked( @@ -366,7 +366,7 @@ fn do_data_changeset(rev: Abbrev) -> Result<(), String> { fn do_data_manifest(rev: Abbrev) -> Result<(), String> { unsafe { - let commit_id = hg2git + let commit_id = HG2GIT .get_note_abbrev(rev) .ok_or_else(|| format!("Unknown manifest id: {}", rev))?; let manifest = RawHgManifest::read(GitManifestId::from_unchecked( @@ -1779,11 +1779,11 @@ fn do_setup() -> Result<(), String> { fn do_data_file(rev: Abbrev) -> Result<(), String> { unsafe { let mut stdout = stdout(); - let blob_id = hg2git + let blob_id = HG2GIT .get_note_abbrev(rev) .ok_or_else(|| format!("Unknown file id: {}", rev))?; let file_id = GitFileId::from_unchecked(BlobId::from_unchecked(blob_id)); - let metadata_id = files_meta + let metadata_id = FILES_META .get_note_abbrev(rev) .map(|oid| GitFileMetadataId::from_unchecked(BlobId::from_unchecked(oid))); let file = RawHgFile::read(file_id, metadata_id).unwrap(); @@ -3124,7 +3124,7 @@ fn do_fsck_full( } if full_fsck && !broken.get() { - unsafe { &mut hg2git }.for_each(|h, _| { + unsafe { &mut HG2GIT }.for_each(|h, _| { if seen_changesets.contains(&HgChangesetId::from_unchecked(h)) || seen_manifests.contains(&HgManifestId::from_unchecked(h)) || seen_files.contains(&HgFileId::from_unchecked(h)) @@ -3139,7 +3139,7 @@ fn do_fsck_full( do_set(SetWhat::File, h, GitObjectId::NULL); do_set(SetWhat::FileMeta, h, GitObjectId::NULL); }); - unsafe { &mut git2hg }.for_each(|g, _| { + unsafe { &mut GIT2HG }.for_each(|g, _| { // TODO: this is gross. let cid = GitChangesetId::from_unchecked(CommitId::from_unchecked(g)); if seen_git2hg.contains(&cid) { diff --git a/src/store.rs b/src/store.rs index 1de99dd91..e0a8d862a 100644 --- a/src/store.rs +++ b/src/store.rs @@ -43,7 +43,7 @@ use crate::hg_bundle::{ use crate::hg_connect_http::HttpRequest; use crate::hg_data::{hash_data, GitAuthorship, HgAuthorship, HgCommitter}; use crate::libcinnabar::{ - files_meta, git2hg, git_notes_tree, hg2git, hg_notes_tree, strslice, strslice_mut, + git_notes_tree, hg_notes_tree, strslice, strslice_mut, FILES_META, GIT2HG, HG2GIT, }; use crate::libgit::{ commit, commit_oid, die, for_each_ref_in, get_oid_blob, object_id, strbuf, Commit, RawBlob, @@ -85,7 +85,7 @@ macro_rules! hg2git { impl $h { pub fn to_git(self) -> Option<$g> { unsafe { - hg2git + HG2GIT .get_note(self.into()) .map(|o| $g::from_raw_bytes(o.as_raw_bytes()).unwrap()) } @@ -114,7 +114,7 @@ pub struct RawGitChangesetMetadata(RawBlob); impl RawGitChangesetMetadata { pub fn read(changeset_id: GitChangesetId) -> Option { - Self::read_from_notes_tree(unsafe { &mut git2hg }, changeset_id) + Self::read_from_notes_tree(unsafe { &mut GIT2HG }, changeset_id) } pub fn read_from_notes_tree( @@ -691,7 +691,7 @@ impl RawHgFile { if oid == Self::EMPTY_OID { Some(Self(vec![].into())) } else { - let metadata = unsafe { files_meta.get_note(oid.into()) } + let metadata = unsafe { FILES_META.get_note(oid.into()) } .map(BlobId::from_unchecked) .map(GitFileMetadataId::from_unchecked); Self::read(oid.to_git().unwrap(), metadata) @@ -1181,10 +1181,10 @@ pub fn do_set(what: SetWhat, hg_id: HgObjectId, git_id: GitObjectId) { match what { SetWhat::Changeset => { if git_id.is_null() { - unsafe { &mut hg2git }.remove_note(hg_id); + unsafe { &mut HG2GIT }.remove_note(hg_id); } else if let Ok(ref mut commit) = CommitId::try_from(git_id) { handle_changeset_conflict(HgChangesetId::from_unchecked(hg_id), commit); - unsafe { &mut hg2git }.add_note(hg_id, (*commit).into()); + unsafe { &mut HG2GIT }.add_note(hg_id, (*commit).into()); } else { die!("Invalid object"); } @@ -1194,13 +1194,13 @@ pub fn do_set(what: SetWhat, hg_id: HgObjectId, git_id: GitObjectId) { if let Some(cid) = csid.to_git() { if git_id.is_null() { unsafe { - git2hg.remove_note(cid.into()); + GIT2HG.remove_note(cid.into()); } } else if BlobId::try_from(git_id).is_err() { die!("Invalid object"); } else { unsafe { - git2hg.add_note(cid.into(), git_id); + GIT2HG.add_note(cid.into(), git_id); } } } else if !git_id.is_null() { @@ -1216,13 +1216,13 @@ pub fn do_set(what: SetWhat, hg_id: HgObjectId, git_id: GitObjectId) { git_id, ))); } - set::(unsafe { &mut hg2git }, hg_id, git_id); + set::(unsafe { &mut HG2GIT }, hg_id, git_id); } SetWhat::File => { - set::(unsafe { &mut hg2git }, hg_id, git_id); + set::(unsafe { &mut HG2GIT }, hg_id, git_id); } SetWhat::FileMeta => { - set::(unsafe { &mut files_meta }, hg_id, git_id); + set::(unsafe { &mut FILES_META }, hg_id, git_id); } } } @@ -2174,9 +2174,9 @@ pub unsafe extern "C" fn init_metadata(c: *const commit) { #[no_mangle] pub unsafe extern "C" fn done_metadata() { - git2hg.done(); - hg2git.done(); - files_meta.done(); + GIT2HG.done(); + HG2GIT.done(); + FILES_META.done(); } pub fn do_store_metadata() -> CommitId { @@ -2188,9 +2188,9 @@ pub fn do_store_metadata() -> CommitId { let mut tree = object_id::default(); let mut previous = None; unsafe { - hg2git_ = hg2git.store(HG2GIT_OID); - git2hg_ = git2hg.store(GIT2HG_OID); - files_meta_ = files_meta.store(FILES_META_OID); + hg2git_ = HG2GIT.store(HG2GIT_OID); + git2hg_ = GIT2HG.store(GIT2HG_OID); + files_meta_ = FILES_META.store(FILES_META_OID); manifests = store_manifests_metadata(); changesets = store_changesets_metadata(); if !METADATA_OID.is_null() {