YN63NUZO4LVJ7XPMURDULTXBVJKW5MVCTZ24R7Z52QMHO3HPDUVQC GMGTWOWOPYCGOD3QEQAF5PSQVZWURAIVU6S6URXNHDAGQSC4P3EAC SPA2OL5ITFMLB5P2WL342QAU2FXPKSFS4XHAMW6HYWOGSGLO2MJAC ZXCRG5RPZU7DKPFI24IRLHV4DZSB6NJKA73J6FC7ARXT2KGOIV7QC ZAEUSICJC3YOWGF6NZEQCQ34PHPRSBCJEP7FIWE6VIWJGVU734HQC NO2QPRFLGCYUDXYJTOY3S3NZJCCLAFOQUHITKDZ7LSZLRLOV5W3QC CZX6TRWR53F2BRLKSUTBPEONKS65IYNBO2FYB4HSWF6OK7DOEJGAC 2BKYJ2JM5PTXWO6HTVBKFQANWWSCJ4UHJYKAXWGTVZB35AZJ76CQC JACZYXK43IU5HWLHQBY3BOAE7CUO6NGEXQ3HSZL3CQP3SLGKMBOAC U4F5G3AU7NBRVVLBLLWU774XAFNB6M5KHK4ENNDQN4FR6HUUNOQQC EGSVRZJVIBSPYAI65A25CH5RYAGL4PUP3B24VSRUS3M4WIUCZWHAC ZZXBHCN3WGJG26SBKZP3ZG4FYUKY7WK2EDSDXLDMQLK7PDKXISPQC KWAGWB73AMLJFK2Z7SBKHHKKHFRX7AQKXCWDN2MBX72RYCNMB36QC 44BN7FWSIXKG75IJUTCXLJE7VANNQFPRHQXTPLQHFU7AKGLSPQRAC LGEJSLTYI7Y2CYC3AN6ECMT3D3MTWCAKZPVQEG5MPM2OBW5FQ46AC JGJOYE3JQD7RJVM2RLMFX4QWOZ62V6RZ4RARBW6JUIJTEQG4ORJQC EQLDTLXVCARE36EJE3S6SNEVTW2JJY4EYD36EX7WSIFLG2XMKKQAC SXEYMYF7P4RZMZ46WPL4IZUTSQ2ATBWYZX7QNVMS3SGOYXYOHAGQC G734WNM64AR5BLAZMN5MDPKSFTYXTUQR6MAGB32NRBC5FXFRWSJAC UZZQ3VIA4YVL7C6P22LBPWWPB4BKH6VQLYKVHGQ3XRFISKM52TRQC CCLLB7OIFNFYJZTG3UCI7536TOCWSCSXR67VELSB466R24WLJSDAC GHO6DWPILBBTL6CVZKERJBTFL3EY6ZT4YM4E5R4S6YPGVFKFHCVAC VO5OQW4W2656DIYYRNZ3PO7TQ4JOKQ3GVWE5ALUTYVMX3WMXJOYQC L4JXJHWXYNCL4QGJXNKKTOKKTAXKKXBJUUY7HFZGEUZ5A2V5H34QC JL4WKA5PBKXRNAMETYO4I52QKASQ3COYHH2JKGA7W5YLIRZZH53AC MU5GSJAW65PEG3BRYUKZ7O37BPHW3MOX3S5E2RFOXKGUOJEEDQ5AC I52XSRUH5RVHQBFWVMAQPTUSPAJ4KNVID2RMI3UGCVKFLYUO6WZAC UDHP4ZVBQZT2VBURB2MDCU2IZDNMCAFSIUKWRBDQ5BWMFKSN2LYQC QE64ATLZWMKHYABCD3VA547PYXCK6YN3K7RE2TX3SCQNKG7XLVAQC Q45QHPO4HDTEZF2W4UDZSYYQ46BPEIWSW4GJILZR5HTJNLKXJABQC KTTKF3RWYAK2YSH2DYYW5QVG4KSNGWUBJBFHKE24OJ7LFCBF5FEAC WLUID7NANDWTN5GOECNEKFTLZF3MUVS7K26YWLYLSGJ56G63NV4QC 3KRGVQFUWFHPOGZOXVTJYNCM4XBRVYITAEOVPKBSAZ5GZIUO5KVQC XA23FMQM2AI7RMR36AYN7UNP2D5JWVJMJPHURWZO7URM7H46PU6AC 76PCXGML77EZWTRI5E6KHLVRAFTJ2AB5YRN5EKOYNAPKTWY2KCGAC X6YFD4WVMUYJCR5IYPJH6UKYVWSA7DKBRVJ6XQFXHOE2TRYUTAHAC WZVCLZKY34KQBQU6YBGJLQCDADBQ67LQVDNRVCMQVY3O3C3EIWSQC TZVUNELWO5SIK7FKUTAR3ORAV2YYDFJ3EO7CTUOBDX4TXZOL5L3AC 64M73LNCB2V57AWAAKHK2NNERXANMV5V3XI3TFC4XR7FLJNCDCRQC SNZ3OAMCPUGFYON5SZHQQQK46ZZMVMJECJYEUCMG657UVLY2PNBQC SLJ3OHD4F6GJGZ3SV2D7DMR3PXYHPSI64X77KZ3RJ24EGEX6ZNQAC YAJAXIV5VL263Z6FYLKFPROB3MQPRPH22P44GRGRVGEP56HOMBOAC 3AMEP2Y5J6GA4AWQONF4JVA3XSR3ASLHHKMYG44R72SOUY3UQCDAC 5DVRL6MFXQOCPOZMYSKBERMRRVUTYRL2SRGRTU2MH4IEOFCDKM3QC VNBLGT6GAN2AHKRFKTKED7WNDDRGNULY5H343ZYV3ETSDZZKGBTAC QMTANHVNRPQ5IX66FYQBFRBDCTN6YKMNCO6OHTQ6QCUASPWWXJKAC MF3WAHBIH6Q2F7ZOKWPEJF6VGSKJITWLR3Z64GTD6YQZNA5EATWQC G6S6PWZEFJK7ARWBIFKDU6VYC5DCJ2YFJMWZOLLWWKU52R2QPXZAC 367UBQ6KNAKUEWG32R4QRJ6H7IE7NAZFOPTC3ZOE4Z6E44RV3ISQC 5HF7C67M4DZMYTCIG32XEQQ662AHQMIHTHUK7TAVSO52XLMFBZPAC HSVGP2G4D2F56DS3YKZLSYPS4A5BNGH4NTAXAOZ57OCXFM3E5AYAC PCEJFKFXAFGYGHMM4BOBGFV3WRFXEBF2UQYQHLJ7MURRYBKRM3EAC BE7GUCI2N6TX3P2HRMFSH7XLJKILDPOKOXKA7HWOABBFNKCKMZLAC PSKXR4QEPPVJZR777HW67IEHUPGZB44MFCNQ2KUS422Q3W22IQWAC AEPEFS7O3YT7CRRFYQVJWUXUUSRGJ6K6XZQVK62B6N74UXOIFWYAC VQPAUKBQ2POZKL7CZFAZK5ZQKEBYL27XZYZWYUSH5AH25KK6DWKAC A6R6SGCPLFM45QNWJLISFBR3EEXVITYHCWEUOPNH4UIGIWJRTZAQC R3H7D42UZ446V5TO2574BMAQQAYYJPEIMSZVDPAGVIYU2COJSWBAC 33SQMZYXPV2A3F7P6WBFKFO2BTQV6THSQXOLV3PCZASC6OTKVHTQC 5BRU2RRWOQBMS2V3RQM7PRFR5UILYZ73GISHAKJA6KIZGC5M2MFAC 7UPL3Y2A5QOBU6VIUHNWEFGSGQ5CMWGDGOVLRZ53UARXG3TDGLMAC KQTD46KVVWMJ3W6O55BEJLCVTNTDLUH6QT46AEFT7OU2SELXG4IAC 6YMDOZIB5LVYLFIDGN2WNT5JTHEAMS4TFPVDEZ3OWXWOKJOC5QDAC NMX52UOGRCY2O7HT7Q45KWISOHNV4PEEMLDYDBJ4QPDIMTVKKJ6AC 3M7WBE24JTPTHWQOU5PO2ZJYKPKEH2F6R4M6RWIRFG334PQEA55QC CXM5CBS27BL35Z6TRCI7OS4AHWVJ4VFND7HECGAUC74ZQ5KFZXLAC LLT3GY6ULCVHMO3VUSVI5H4O244Z3ULOWLTW2IGJXIA2TWIHJDSQC VYHHOEYHO67JNJEODX5L3CQFIV3DAXZBBIQUOMCWJDYF3VWICDNQC ZXTHL45OYLOICXTXXEQ6AMNSLMQFZ6BFUJWMO6LZOSDK7ERROC5AC KDF6FJRVF72L274BEUJCTUKRFMNL6BDZMTVKDPEYGFX4TC3YOVSQC PJ7T2VFLV5PYG3CV23GC2GIQETXKGC6CO74JBGREV3JC3LG5OXUAC BZCGXVS77ZS3N4QPLIHNWZ3YFVV7H4PXQD3U6RN5ZFVOC7QL7MBQC V2MDXX622MAXHXGLX7ERVKGYZVZDCYJIFET3TGGIK455XIADYJUAC 3YDPHBANMNSK7Z5SCG745VLTP4BBQWIXCJTQOSDI6UJGYR6S45EQC QNJBR73KCSCCF6FTHGZDF2K7PZQL3EFKZFOBT77KYZBMALTTW6OQC 6RVT5X4LTRP5XHVDESXMIC2DHMT5MUQ24ZDWEBJ4XYTF6LJXK7CAC HMMMKONLCRAXVT7SO2ITTFDOJIQKKVSRIZPXYVPDC34RCBHWMHVAC BD5PC25AB5MKVIYDFSDGRZ4YGX4PKW4SMZ3YAYAPNA5HLDVJUR3QC BXD3IQYNMKMI5BTANCF6NZHZP4CKPWADGJMBT2R3WTMKVKONT5QAC IM6UFPOZHZTBMESRXGBALOAWJWUUDGLP2TVLSZ3RZPSJITKB3R7QC 27PYHR6LO4M4RMSMLVMUKSYNQ72V6RRMRXLYQI3JA3LBHJO747YAC ATZ3BWSEFJBLVGDUZFESRNHVCIO6ZRZ3ALPANZSVGVO7A5BUAFQQC BZSC7VMYSFRXDHDDAMCDR6X67FN5VWIBOSE76BQLX7OCVOJFUA3AC OJZWJUF2TCGZ7RFVY6FPKBS5P3C4BGHZDPVH775OHVNVFMJICKNQC LCERQSWMA2YKOPAPNZUSOQ7FLBGDHBZR33OHLYX7T4KTKULRMJDQC 6T5ULULMRGU5GJ3JQTEH2QFQN5IMP53TYFFXUT5UE6FA6WWFFMFAC 7T5STZYBIUN5AQPFKASNYO24QFLNBX3YCE4YIIXEQNJYR5LSZ6EQC KD4JIMAE6M2LFWEHFPEL4RTRV7UWYWNGGS52N2TKQ42ZNFSNLCEQC 7A2TSC4PAKK3WOH3DMAJASCEC6D5JLJWNFWJTEEBE4CVS4K76PPQC L5PHFTIERPDAFIOSHZSMAN2CUSFM626ISMGTDYRN5KWPLXCOVPXAC UNZXTNSJI4YRY3EQ3M4HMBKQDNYDTY6B7IZRBNYGDJXTA2UKYWRAC ZRUPLBBTT4S6S7A3LOAHG4ONYEGPA5CFO4L2XBCNFKK45MWX3BDAC 65S67T3EKKLFRBCU73Z542V7A4JSMGP37OJINON6N563UIBQAITAC 73NW2X2MI767RYNTKS67ZB5QUWYEAA4SCORLD52K36ZU3JAK67AQC 7PM25EXLNQ6JUUIZNTAOQYNNIZNG6TJREEBUSAIC3FIOE7FHETSAC GVQ7YSEDDCYYYWDJ5JUVFSBWA5EZVOZJI63KK6E46N6Y2B6LP72AC 43AJ37IXON6PMMYRZM6OB2MJXPYCNIWW2XBDVNBXIRH5DD7JDTVQC NA5I4WYNE2O3LPSHXGWXW7XL4YNYFDREEGDOP6LJ5HJXTQDXM7BAC 3WIQYEISUMGOL5FY4LCWOJS55CTTQA7WMJZXAE3Q4GQUTBFLAE7QC WEHUTJUKHOJIBMEK2M7ILPK532FMO7YGWTEAHOIXZP5WOOOSF3ZAC 6DOXSHWGKJIMIPFCNLASGKBAJCJMJULW5HFRZAZ67EYSMXXGJ3KAC H62VFFJEBL2I3O4D3BAJZ57ROPWUISC7JCDIWFBC5DAYJRHMMDXAC LYTVEPH3W5UHF7MAYFWBT6NVNC42HEVKJGGMFDKUDZDNDOI33YJQC XWETQ4DE4KL2GQWSEBE5NENLTSLIDF7RIWOCCVWJFQOVQJE5P33AC JRENVH5DF2F4SOV7UNJENFA7VDI3H63XK76R3LFZK6QCW7JIBLSQC UFCZKKLXVYQYQBYENCAFHY3ZPPSDAJJAIREZSYNQM4QNXV6G6RXAC TPEH2XNBS5RO4IEVKENVF6P65AH7IX64KK2JAYMSJT3J5GXO67EAC ENKQ3QZGH2QW246C7GSZRKYLODJOQHKZZSYV7QHB7VPOFP5PASVQC B3QWIGDERNMB3M6P5WTWP5CN2DB3KCS7MVTEPC2XVJ237ZXVQGMAC A3DMBJJAPLS6ASSZ7JVVVULRQNZCF2WKYTRUD7EY7PKVYABSATFAC B5Z4IMEUYAEJPOU5EIAXI7VYZVUM6CWKV7CTSOXK3F4GXTNNMMAAC JMBGCWM5FYXPAMTU5R7UCMBIHJMUVCT44B6KGQ7P7XZRX662TC4QC BT2ZHPY4LTECZDNPNLX5IUAEA6CYB4RRBGVBXUNK3ARHMWQK7KHAC (import(fetchTarball {url = "https://github.com/edolstra/flake-compat/archive/c71d063a2fce96001c7ef99b301dfbd0c29ebde1.tar.gz";sha256 = "0vnbhqf0lc4mf2zmzqbfv6kqj9raijxz8xfaimxihz3c6s5gma2x";}){ src = ./.; }).shellNix.default
with import <nixpkgs> {};stdenv.mkDerivation {name = "Pijul";buildInputs = with pkgs; [xxHashzstdlibsodiumopensslpkgconfig] ++ lib.optionals stdenv.isDarwin(with darwin.apple_sdk.frameworks; [CoreServicesSecuritySystemConfiguration]);}# (import# (fetchTarball {# url = "https://github.com/edolstra/flake-compat/archive/c71d063a2fce96001c7ef99b301dfbd0c29ebde1.tar.gz";# sha256 = "0vnbhqf0lc4mf2zmzqbfv6kqj9raijxz8xfaimxihz3c6s5gma2x";# })# { src = ./.; }).shellNix.default
};let pre_ = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());let pre = if !pre_.is_empty() {quote! {let (key, value) = #pre_;}} else {quote! {}};let post_ = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());let post = if post_.is_empty() {quote! { if let Ok(x) = self.txn.get(&self.#name, key, value) {Ok(x)} else {Err(TxnErr(SanakirjaError::PristineCorrupt))}}} else {quote! { if let Ok(x) = self.txn.get(&self.#name, key, value) {Ok(x . #post_)} else {Err(TxnErr(SanakirjaError::PristineCorrupt))}}
fn #name_get <'txn> (&'txn self, key: #key, value: Option<#value>) -> Result<Option<#value>, TxnErr<Self::#error>> {use ::sanakirja::Transaction;#pre#post
fn #name_get <'txn> (&'txn self, key: &#key, value: Option<&#value>) -> Result<Option<&'txn #value>, TxnErr<Self::#error>> {match ::sanakirja::btree::get(&self.txn, &self.#name, key, value) {Ok(Some((k, v))) if k == key => Ok(Some(v)),Ok(_) => Ok(None),Err(e) => {error!("{:?}", e);Err(TxnErr(SanakirjaError::PristineCorrupt))}}
fn #name_get(&self, db: &Self::#name_capital, key: #key, value: Option<#value>) -> Result<Option<#value>, TxnErr<Self::#error>> {use ::sanakirja::Transaction;if let Ok(x) = self.txn.get(db, key, value) {Ok(x)} else {Err(TxnErr(SanakirjaError::PristineCorrupt))
fn #name_get<'txn>(&'txn self, db: &Self::#name_capital, key: &#key, value: Option<&#value>) -> Result<Option<&'txn #value>, TxnErr<Self::#error>> {match ::sanakirja::btree::get(&self.txn, db, key, value) {Ok(Some((k, v))) if k == key => Ok(Some(v)),Ok(_) => Ok(None),Err(e) => {error!("{:?}", e);Err(TxnErr(SanakirjaError::PristineCorrupt))}
fn #name_get<'txn>(&'txn self, db: &Self::#name_capital, key: #key, value: Option<#value>) -> Result<Option<#value>, TxnErr<Self::#error>>;
fn #name_get<'txn>(&'txn self, db: &Self::#name_capital, key: &#key, value: Option<&#value>) -> Result<Option<&'txn #value>, TxnErr<Self::#error>>;
let pre = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());let post = proc_macro2::TokenStream::from_iter(next(&mut input_iter).into_iter());let pre_init = if !pre.is_empty() {quote! { let pos = #pre; }} else {quote! {}};let post = if !post.is_empty() {quote! { . #post }} else {quote! {}};
#pre_initif let Ok((cursor, _)) = txn.txn.set_cursors(&db, pos) {Ok(Cursor {cursor,txn,marker: std::marker::PhantomData,})} else {Err(TxnErr(SanakirjaError::PristineCorrupt))
let mut cursor = ::sanakirja::btree::cursor::Cursor::new(&txn.txn, &db)?;if let Some((k, v)) = pos {cursor.set(&txn.txn, k, v)?;
#pre_initlet mut cursor = if pos.is_some() {if let Ok((x, _)) = self.txn.set_cursors(&db, pos) {x} else {return Err(TxnErr(SanakirjaError::PristineCorrupt))}} else if let Ok(x) = self.txn.set_cursors_last(&db) {x
let mut cursor = ::sanakirja::btree::cursor::Cursor::new(&self.txn, &db)?;if let Some((k, v)) = pos {cursor.set(&self.txn, k, v)?;
#pre_initlet mut cursor = if let Ok((x, _)) = self.txn.set_cursors(&db, pos) {x} else {return Err(TxnErr(SanakirjaError::PristineCorrupt))};
let mut cursor = ::sanakirja::btree::cursor::Cursor::new(&self.txn, &db)?;if let Some((k, v)) = pos {cursor.set(&self.txn, k, v)?;}
) -> Result<Option<(#key, #value)>, TxnErr<SanakirjaError>> {let x = if let Ok(x) = unsafe { ::sanakirja::next(&self.txn, cursor) } {
) -> Result<Option<(&'txn #key, &'txn #value)>, TxnErr<SanakirjaError>> {let x = if let Ok(x) = cursor.next(&self.txn) {
) -> Result<Option<(#key, #value)>, TxnErr<SanakirjaError>> {let x = if let Ok(x) = unsafe { ::sanakirja::prev(&self.txn, cursor) } {
) -> Result<Option<(&'txn #key, &'txn #value)>, TxnErr<SanakirjaError>> {let x = if let Ok(x) = cursor.next(&self.txn) {
impl<T: #txnt, RT: std::ops::Deref<Target = T>>crate::pristine::Cursor<T, RT, T::#cursor_name, #key, #value>
impl<'a, T: #txnt>crate::pristine::Cursor<T, &'a T, T::#cursor_name, #key, #value>
if pre_key.is_empty() {proc_macro::TokenStream::from(quote! {fn #put(&mut self,k: #key,v: #value,) -> Result<bool, TxnErr<Self::#error>> {Ok(self.txn.put(&mut self.rng, &mut self.#name, k, v).map_err(TxnErr)?)}fn #del(&mut self,k: #key,v: Option<#value>,) -> Result<bool, TxnErr<Self::#error>> {Ok(self.txn.del(&mut self.rng, &mut self.#name, k, v).map_err(TxnErr)?)}})} else {proc_macro::TokenStream::from(quote! {fn #put(&mut self,k: #key,v: #value,) -> Result<bool, TxnErr<Self::#error>> {let k = #pre_key;let v = #pre_value;Ok(self.txn.put(&mut self.rng, &mut self.#name, k, v).map_err(TxnErr)?)}fn #del(&mut self,k: #key,v: Option<#value>,) -> Result<bool, TxnErr<Self::#error>> {let k = #pre_key;let v = v.map(|v| #pre_value);Ok(self.txn.del(&mut self.rng, &mut self.#name, k, v).map_err(TxnErr)?)}})}
proc_macro::TokenStream::from(quote! {fn #put(&mut self,k: &#key,v: &#value,) -> Result<bool, TxnErr<Self::#error>> {Ok(::sanakirja::btree::put(&mut self.txn, &mut self.#name, k, v).map_err(TxnErr)?)}fn #del(&mut self,k: &#key,v: Option<&#value>,) -> Result<bool, TxnErr<Self::#error>> {Ok(::sanakirja::btree::del(&mut self.txn, &mut self.#name, k, v).map_err(TxnErr)?)}})
impl Lock {pub async fn mut_txn_lock<P: AsRef<Path>>(p: P) -> Result<Self, anyhow::Error> {let pp = p.as_ref().join("db_lock");Ok(Lock::MutTxn(mut_txn(&pp).await?))}pub async fn txn_lock<P: AsRef<Path>>(p: P) -> Result<Self, anyhow::Error> {let pp = p.as_ref().join("db_lock");Ok(Lock::Txn(txn(&pp).await?))}pub async fn commit(&mut self) -> Result<(), anyhow::Error> {match self {Lock::MutTxn(m) => m.commit().await,_ => Ok(()),}}}}use crate::{config, current_dir};
lock: if mutable {lock::Lock::mut_txn_lock(&pristine_dir).await?} else {lock::Lock::txn_lock(&pristine_dir).await?},pristine: unsafe {libpijul::pristine::sanakirja::Pristine::new_nolock(&pristine_dir)?},
pristine: libpijul::pristine::sanakirja::Pristine::new(&pristine_dir.join("db"))?,
} else if let Ok(data) = std::str::from_utf8(&data) {for l in data.lines() {
} else {debug!("{:?}", data);let mut p = 0;while let Some(i) = (&data[p..]).iter().position(|i| *i == b'\n') {let line = if !pending.is_empty() {pending.extend(&data[p..p + i]);&pending} else {&data[p..p + i]};let l = std::str::from_utf8(line)?;
Ok(())}pub async fn clone_channel<T: TxnTExt + MutTxnTExt>(&mut self,repo: &mut Repository,txn: &mut T,channel: &mut ChannelRef<T>,lazy: bool,) -> Result<(), anyhow::Error> {let (sender, mut recv) = tokio::sync::mpsc::channel(10);*self.state.lock().await = State::Channel { sender };self.run_protocol().await?;debug!("clone channel");self.c.data(format!("channel {}\n", self.channel).as_bytes()).await?;let progress = indicatif::ProgressBar::new_spinner();progress.set_style(indicatif::ProgressStyle::default_spinner().template("{spinner} Cloning channel"),);progress.enable_steady_tick(100);*PROGRESS.lock().await = Some(progress);let from_dump_alive = {let mut from_dump =libpijul::pristine::channel_dump::ChannelFromDump::new(txn, channel.clone());debug!("receiving channel");while let Some(msg) = recv.recv().await {debug!("msg = {:?}", msg.len());if from_dump.read(&msg)? {debug!("break");break;}}debug!("from dump done");from_dump.alive};if let Some(ref mut progress) = *PROGRESS.lock().await {progress.set_style(indicatif::ProgressStyle::default_spinner().template("✓ Cloning channel"),);progress.finish();}let channel_ = channel.borrow();debug!("cloned, now downloading changes");let mut hashes = Vec::new();if lazy {for &ch in from_dump_alive.iter() {let h = txn.get_external(ch)?.unwrap();hashes.push(h);}} else {for h in txn.log(&channel_, 0)? {hashes.push((h?.1).0);}}std::mem::drop(channel_);debug!("hashes = {:#?}", hashes);self.download_changes_(&hashes, None, &mut repo.changes_dir, true).await?;txn.output_repository_no_pending(&mut repo.working_copy,&repo.changes,channel,"",true,None,)?;
let (mut b, (_, state)) = if let Some(last) = txn.last_remote(remote)? {last
let (mut b, state): (_, Merkle) = if let Some((u, v)) = txn.last_remote(remote)? {debug!("dichotomy_changelist: {:?} {:?}", u, v);(u, (&v.b).into())
if let RemoteRepo::Ssh(ref mut s) = self {s.clone_channel(repo, txn, channel, lazy).await?;let mut to_unrecord = Vec::new();let mut found = false;for x in txn.iter_rev_remote(&remote.borrow().remote, None)? {let (n, (h, s)) = x?;debug!("{:?} {:?} {:?}", n, h, s);if s == state {found = true;break;}to_unrecord.push(h);}if !found {bail!("State not found: {:?}", state)}self.pull(repo, txn, channel, &to_unrecord, &HashSet::new(), false).await?;for unrec in to_unrecord.iter() {txn.unrecord(&repo.changes, channel, unrec)?;}return Ok(());}
for x in libpijul::pristine::changeid_log(txn, chan, from)? {let (n, (u, _)) = x?;debug!("{:?} {:?} {:?}", n, u, from);
for x in libpijul::pristine::changeid_log(txn, chan, from.into())? {let (n, p) = x?;let n: u64 = (*n).into();debug!("{:?} {:?} {:?}", n, p, from);
} else if let Some(cap) = CHANNEL.captures(&buf) {let channel = load_channel(&txn, &cap[1])?;let channel = channel.borrow();for d in libpijul::pristine::channel_dump::dump_channel(&txn, channel)? {o.write_all(&d?)?;}o.flush()?;
if let Some(inode) = txn.get_revinodes(pos, None)? {del_inodes_with_rev(txn, inode, pos)?;
if let Some(&inode) = txn.get_revinodes(&pos, None)? {del_inodes_with_rev(txn, &inode, &pos)?;
assert!(txn.get_revdep(change_id, None)?.is_none());while txn.del_dep(change_id, None)? {}txn.del_external(change_id, None)?;txn.del_internal(*hash, None)?;
assert!(txn.get_revdep(&change_id, None)?.is_none());while txn.del_dep(&change_id, None)? {}txn.del_external(&change_id, None)?;txn.del_internal(&hash.into(), None)?;
if !e.flag.is_deleted() {if e.flag.is_parent() {if !e.flag.is_folder() {let up_v = txn.find_block_end(channel, e.dest)?;ws.up.insert(up_v, new_vertex.inode);
if !e.flag().is_deleted() {if e.flag().is_parent() {if !e.flag().is_folder() {let up_v = txn.find_block_end(channel, e.dest())?;ws.up.insert(*up_v, new_vertex.inode);
let down_v = txn.find_block(channel, e.dest)?;ws.down.insert(down_v, new_vertex.inode);if e.flag.is_folder() {ws.apply.missing_context.files.insert(down_v);
let down_v = txn.find_block(channel, e.dest())?;ws.down.insert(*down_v, new_vertex.inode);if e.flag().is_folder() {ws.apply.missing_context.files.insert(*down_v);
if e.flag.contains(EdgeFlags::PARENT)|| e.dest != b.start_pos()|| e.introduced_by.is_root()|| e.introduced_by == current_id
if e.flag().contains(EdgeFlags::PARENT)|| e.dest() != b.start_pos()|| e.introduced_by().is_root()|| e.introduced_by() == current_id
if e.flag.contains(EdgeFlags::PARENT) {let u = txn.find_block_end(channel, e.dest)?;e.flag -= EdgeFlags::PARENT;del_graph_with_rev(txn, channel, e.flag, u, v, e.introduced_by)?;
if e.flag().contains(EdgeFlags::PARENT) {let u = *txn.find_block_end(channel, e.dest())?;e -= EdgeFlags::PARENT;del_graph_with_rev(txn, channel, e.flag(), u, v, e.introduced_by())?;
let w = txn.find_block(channel, e.dest)?;del_graph_with_rev(txn, channel, e.flag, v, w, e.introduced_by)?;
let w = *txn.find_block(channel, e.dest())?;del_graph_with_rev(txn, channel, e.flag(), v, w, e.introduced_by())?;
assert_eq!(repo.list_files(), vec!["file"]);
// Checking that unrecord doesn't delete `dir`, and moves `file`// back to the root.let mut files = repo.list_files();files.sort();assert_eq!(files, vec!["dir", "file"]);
apply::apply_change(&changes, &mut txn2, &mut channel2, h0)?;output::output_repository_no_pending(&mut repo2, &changes, &mut txn2, &mut channel2, "", true)?;apply::apply_change(&changes, &mut txn3, &mut channel3, h0)?;output::output_repository_no_pending(&mut repo3, &changes, &mut txn3, &mut channel3, "", true)?;
apply::apply_change(&changes, &mut txn2, &mut channel2, &h0)?;output::output_repository_no_pending(&mut repo2, &changes, &mut txn2, &mut channel2, "", true, None)?;apply::apply_change(&changes, &mut txn3, &mut channel3, &h0)?;output::output_repository_no_pending(&mut repo3, &changes, &mut txn3, &mut channel3, "", true, None)?;
apply::apply_change(&changes, &mut txn, &mut channel, h2)?;apply::apply_change(&changes, &mut txn, &mut channel, h3)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true)?;
apply::apply_change(&changes, &mut txn, &mut channel, &h2)?;apply::apply_change(&changes, &mut txn, &mut channel, &h3)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true, None)?;
apply::apply_change(&changes, &mut txn2, &mut channel2, h0)?;output::output_repository_no_pending(&mut repo2, &changes, &mut txn2, &mut channel2, "", true)?;
apply::apply_change(&changes, &mut txn2, &mut channel2, &h0)?;output::output_repository_no_pending(&mut repo2, &changes, &mut txn2, &mut channel2, "", true, None)?;
output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true)?;let files = repo.list_files();if !files.is_empty() {panic!("Files should be empty {:?}", files);}
output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true, None)?;// Checking that unrecord doesn't delete files on the filesystem,// but updates the tree/revtree tables.let mut files = repo.list_files();files.sort();assert_eq!(files, &["dir", "dir/file"]);
apply::apply_change(&changes, &mut txn, &mut channelb, ha)?;apply::apply_change(&changes, &mut txn, &mut channela, hb)?;
apply::apply_change(&changes, &mut txn, &mut channelb, &ha).unwrap();apply::apply_change(&changes, &mut txn, &mut channela, &hb).unwrap();
let resb = record_all(&mut repo, &changes, &mut txn, &mut channela, "")?;debug_to_file(&txn, &channela.borrow(), "debugres")?;
let resb = record_all(&mut repo, &changes, &mut txn, &mut channela, "").unwrap();debug_to_file(&txn, &channela.borrow(), "debugres").unwrap();
let h_inv = changes.save_change(&p_inv)?;apply::apply_change(&changes, &mut txn, &mut channela, h_inv)?;debug_to_file(&txn, &channela.borrow(), "debug")?;Ok(())
let h_inv = changes.save_change(&p_inv).unwrap();apply::apply_change(&changes, &mut txn, &mut channela, &h_inv).unwrap();debug_to_file(&txn, &channela.borrow(), "debug").unwrap();
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h2)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_h2)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h2)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_h2)?;
apply::apply_change(&changes, &mut txn, &mut channel, p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true)
apply::apply_change(&changes, &mut txn, &mut channel, &p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true, None)
apply::apply_change(&changes, &mut txn, &mut channel, p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true)
apply::apply_change(&changes, &mut txn, &mut channel, &p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true, None)
apply::apply_change(&changes, &mut txn, &mut channel, p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true)
apply::apply_change(&changes, &mut txn, &mut channel, &p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true, None)
apply::apply_change(&changes, &mut txn, &mut channel, p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true)
apply::apply_change(&changes, &mut txn, &mut channel, &p)?;output::output_repository_no_pending(&mut repo, &changes, &mut txn, &mut channel, "", true, None)
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, bob_h)?;apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, alice_h)?;
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, &bob_h)?;apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, &alice_h)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, charlie_h)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &charlie_h)?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, charlie_h)?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, &alice_h)?;apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, &charlie_h)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, charlie_h)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_h)?;apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &charlie_h)?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, alice_h)?;apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, charlie_h)?;
apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, &alice_h)?;apply::apply_change(&changes, &mut txn_bob, &mut channel_bob, &charlie_h)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_h).unwrap();apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, bob_resolution).unwrap();
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_h).unwrap();apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &bob_resolution).unwrap();
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, init_h).unwrap();apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, alice_h).unwrap();
apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, &init_h).unwrap();apply::apply_change(&changes, &mut txn_charlie, &mut channel_charlie, &alice_h).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_bob, alice_h).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_bob, charlie_h).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_bob, &alice_h).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_bob, &charlie_h).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_charlie, alice_h).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_charlie, bob_h).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_charlie, &alice_h).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_charlie, &bob_h).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_charlie, resolution).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_charlie, resolution2).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_charlie, &resolution).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_charlie, &resolution2).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_bob, alice_h)?;apply::apply_change(&changes, &mut txn, &mut channel_bob, resolution)?;
apply::apply_change(&changes, &mut txn, &mut channel_bob, &alice_h)?;apply::apply_change(&changes, &mut txn, &mut channel_bob, &resolution)?;
apply::apply_change(&changes, &mut txn, &mut channel_bob, alice_h)?;apply::apply_change(&changes, &mut txn, &mut channel_bob, resolution)?;
apply::apply_change(&changes, &mut txn, &mut channel_bob, &alice_h)?;apply::apply_change(&changes, &mut txn, &mut channel_bob, &resolution)?;
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, p_bob).unwrap();apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, resolution).unwrap();
apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &p_bob).unwrap();apply::apply_change(&changes, &mut txn_alice, &mut channel_alice, &resolution).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_bob, alice_h)?;apply::apply_change(&changes, &mut txn, &mut channel_bob, resolution)?;
apply::apply_change(&changes, &mut txn, &mut channel_bob, &alice_h)?;apply::apply_change(&changes, &mut txn, &mut channel_bob, &resolution)?;
apply::apply_change(&changes, &mut txn, &mut channel_alice, bob_h1)?;apply::apply_change(&changes, &mut txn, &mut channel_alice, bob_h2)?;apply::apply_change(&changes, &mut txn, &mut channel_alice, bob_h3)?;
apply::apply_change(&changes, &mut txn, &mut channel_alice, &bob_h1)?;apply::apply_change(&changes, &mut txn, &mut channel_alice, &bob_h2)?;apply::apply_change(&changes, &mut txn, &mut channel_alice, &bob_h3)?;
apply::apply_change(&changes, &mut txn, &mut channel_bob, alice_h1).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_bob, alice_h2).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_bob, alice_h3).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_bob, &alice_h1).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_bob, &alice_h2).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_bob, &alice_h3).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_charlie, init_h)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, alice_h1)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, alice_h2)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, alice_h3)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, bob_h1)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, bob_h2)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, bob_h3)?;
apply::apply_change(&changes, &mut txn, &mut channel_charlie, &init_h)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, &alice_h1)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, &alice_h2)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, &alice_h3)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, &bob_h1)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, &bob_h2)?;apply::apply_change(&changes, &mut txn, &mut channel_charlie, &bob_h3)?;
apply::apply_change(&changes, &mut txn, &mut channel_charlie, alices_resolution).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_charlie, bobs_resolution).unwrap();
apply::apply_change(&changes, &mut txn, &mut channel_charlie, &alices_resolution).unwrap();apply::apply_change(&changes, &mut txn, &mut channel_charlie, &bobs_resolution).unwrap();
apply::apply_change(&store, &mut txn2, &mut channel2, h0)?;apply::apply_change(&store, &mut txn2, &mut channel2, h1)?;apply::apply_change(&store, &mut txn2, &mut channel2, h2)?;output::output_repository_no_pending(&mut repo2, &store, &mut txn2, &mut channel2, "", true)?;
apply::apply_change(&store, &mut txn2, &mut channel2, &h0)?;apply::apply_change(&store, &mut txn2, &mut channel2, &h1)?;apply::apply_change(&store, &mut txn2, &mut channel2, &h2)?;output::output_repository_no_pending(&mut repo2, &store, &mut txn2, &mut channel2, "", true, None)?;
apply::apply_change(&store, &mut txn2, &mut channel2, h3)?;output::output_repository_no_pending(&mut repo2, &store, &mut txn2, &mut channel2, "", true)?;
apply::apply_change(&store, &mut txn2, &mut channel2, &h3)?;output::output_repository_no_pending(&mut repo2, &store, &mut txn2, &mut channel2, "", true, None)?;
impl std::ops::Deref for SmallString {type Target = SmallStr;fn deref(&self) -> &Self::Target {let len = self.len as usize;unsafe {std::mem::transmute(std::slice::from_raw_parts(self as *const Self as *const u8, 1 + len))}}}impl AsRef<SmallStr> for SmallString {fn as_ref(&self) -> &SmallStr {let len = self.len as usize;unsafe {std::mem::transmute(std::slice::from_raw_parts(self as *const Self as *const u8, 1 + len))}}}impl AsMut<SmallStr> for SmallString {fn as_mut(&mut self) -> &mut SmallStr {let len = self.len as usize;unsafe {std::mem::transmute(std::slice::from_raw_parts_mut(self as *mut Self as *mut u8, 1 + len))}}}impl std::ops::DerefMut for SmallString {fn deref_mut(&mut self) -> &mut Self::Target {let len = self.len as usize;unsafe {std::mem::transmute(std::slice::from_raw_parts_mut(self as *mut Self as *mut u8, 1 + len))}}}
}/// ```ignore/// use libpijul::small_string::*;/// let mut s = SmallString::from_str("blah");/// let s_ = s.as_small_str();/// let s2_ = s_;/// let s3_ = s_.clone();/// assert_eq!(s_, s2_);/// assert_eq!(s_, s3_);/// ```pub fn as_small_str(&self) -> SmallStr {SmallStr {p: self as *const SmallString as *const u8,marker: std::marker::PhantomData,}
/// An internal "unsafe" version of a [`small_string::SmallStr`], used/// to circumvent the absence of associated type constructors in Rust/// (else this would be borrow on a table).#[derive(Clone, Copy)]#[doc(hidden)]pub struct UnsafeSmallStr(*const u8);
impl sanakirja::UnsizedStorable for SmallStr {const ALIGN: usize = 1;
unsafe fn write_to_page(&self, p: *mut u8) {std::ptr::copy(&self.len, p, 1 + self.len as usize);debug!("writing {:?}", std::slice::from_raw_parts(p, 1+self.len as usize));}unsafe fn from_raw_ptr<'a, T>(_: &T, p: *const u8) -> &'a Self {smallstr_from_raw_ptr(p)}unsafe fn onpage_size(p: *const u8) -> usize {let len = *p as usize;debug!("onpage_size {:?}", std::slice::from_raw_parts(p, 1+len as usize));1 + len}
impl sanakirja::Representable for UnsafeSmallStr {fn alignment() -> sanakirja::Alignment {sanakirja::Alignment::B1}fn onpage_size(&self) -> u16 {unsafe {let len = (*self.0) as u16;1 + len}}unsafe fn write_value(&self, p: *mut u8) {std::ptr::copy(self.0, p, self.onpage_size() as usize)}unsafe fn read_value(p: *const u8) -> Self {UnsafeSmallStr(p)}unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {let a = UnsafeSmallStr(self.0).to_small_str();let b = x.to_small_str();a.as_str().cmp(b.as_str())}type PageOffsets = std::iter::Empty<u64>;fn page_offsets(&self) -> Self::PageOffsets {std::iter::empty()
unsafe fn smallstr_from_raw_ptr<'a>(p: *const u8) -> &'a SmallStr {let len = *p as usize;std::mem::transmute(std::slice::from_raw_parts(p, 1 + len as usize))}#[test]fn smallstr_repr() {use sanakirja::UnsizedStorable;let o = SmallString::from_str("blablabla");let mut x = vec![0u8; 200];unsafe {o.write_to_page(x.as_mut_ptr());let p = smallstr_from_raw_ptr(x.as_ptr());assert_eq!(p.as_str(), "blablabla")
let end = ChangePosition(self.rec.contents.len() as u64);self.rec.largest_file = self.rec.largest_file.max(end.0 - start.0);
let end = ChangePosition(self.rec.contents.len().into());self.rec.largest_file = self.rec.largest_file.max(end.0.as_u64() - start.0.as_u64());
let child = txn.find_block(channel, child.dest).unwrap();for grandchild in iter_adjacent(txn, channel, child, f0, f1)? {
let child = txn.find_block(channel, child.dest()).unwrap();for grandchild in iter_adjacent(txn, channel, *child, f0, f1)? {
assert!(parent.flag.contains(EdgeFlags::FOLDER));let parent_dest = txn.find_block_end(channel, parent.dest).unwrap();
assert!(parent.flag().contains(EdgeFlags::FOLDER));let parent_dest = txn.find_block_end(channel, parent.dest()).unwrap();
assert!(grandparent.flag.contains(EdgeFlags::PARENT));assert!(grandparent.flag.contains(EdgeFlags::FOLDER));
assert!(grandparent.flag().contains(EdgeFlags::PARENT));assert!(grandparent.flag().contains(EdgeFlags::FOLDER));
previous: parent.flag - EdgeFlags::PARENT,flag: (parent.flag - EdgeFlags::PARENT) | EdgeFlags::DELETED,from: parent.dest.to_option(),
previous: parent.flag() - EdgeFlags::PARENT,flag: (parent.flag() - EdgeFlags::PARENT) | EdgeFlags::DELETED,from: parent.dest().to_option(),
pub(crate) const ROOT: ChangePosition = ChangePosition(0);pub(crate) const BOTTOM: ChangePosition = ChangePosition(1);
pub(crate) const ROOT: ChangePosition = ChangePosition(L64(0u64));pub(crate) const BOTTOM: ChangePosition = ChangePosition(L64(1u64.to_le()));
(self.0 - x.0) as usize
let a: u64 = self.0.into();let b: u64 = x.0.into();(a - b) as usize}}impl ChangePosition {pub(crate) fn us(&self) -> usize {u64::from_le((self.0).0) as usize}}impl From<ChangePosition> for u64 {fn from(f: ChangePosition) -> u64 {u64::from_le((f.0).0)
use crate::small_string;use ::sanakirja::{Alignment, Commit, Db, Representable, Transaction, UnsafeDb};use byteorder::{ByteOrder, LittleEndian};use rand::rngs::ThreadRng;use rand::thread_rng;
use ::sanakirja::*;
channels: txn.root(Root::Channels as usize)?,external: txn.root(Root::External as usize)?,internal: txn.root(Root::Internal as usize)?,inodes: txn.root(Root::Inodes as usize)?,revinodes: txn.root(Root::RevInodes as usize)?,tree: txn.root(Root::Tree as usize)?,revtree: txn.root(Root::RevTree as usize)?,revdep: txn.root(Root::RevDep as usize)?,touched_files: txn.root(Root::TouchedFiles as usize)?,rev_touched_files: txn.root(Root::RevTouchedFiles as usize)?,partials: txn.root(Root::Partials as usize)?,dep: txn.root(Root::Dep as usize)?,remotes: txn.root(Root::Remotes as usize)?,rng: thread_rng(),
channels: txn.root_db(Root::Channels as usize)?,external: txn.root_db(Root::External as usize)?,internal: txn.root_db(Root::Internal as usize)?,inodes: txn.root_db(Root::Inodes as usize)?,revinodes: txn.root_db(Root::RevInodes as usize)?,tree: txn.root_db(Root::Tree as usize)?,revtree: txn.root_db(Root::RevTree as usize)?,revdep: txn.root_db(Root::RevDep as usize)?,touched_files: txn.root_db(Root::TouchedFiles as usize)?,rev_touched_files: txn.root_db(Root::RevTouchedFiles as usize)?,partials: txn.root_db(Root::Partials as usize)?,dep: txn.root_db(Root::Dep as usize)?,remotes: txn.root_db(Root::Remotes as usize)?,
pub type Txn = GenericTxn<::sanakirja::Txn<::sanakirja::Exclusive, Arc<::sanakirja::Env<::sanakirja::Exclusive>>>,>;pub type MutTxn<T> =GenericTxn<::sanakirja::MutTxn<Arc<::sanakirja::Env<::sanakirja::Exclusive>>, T>>;
pub type Txn = GenericTxn<::sanakirja::Txn<Arc<::sanakirja::Env>>>;pub type MutTxn<T> = GenericTxn<::sanakirja::MutTxn<Arc<::sanakirja::Env>, T>>;
partials: Db<UnsafeSmallStr, Position<ChangeId>>,channels: Db<UnsafeSmallStr, (Graph, ChangeSet, RevChangeSet, ChannelStates, u64, u64)>,remotes: Db<UnsafeSmallStr, (Db<u64, (Hash, Merkle)>, Db<Hash, u64>, Db<Merkle, u64>)>,rng: ThreadRng,open_channels: RefCell<HashMap<SmallString, ChannelRef<Self>>>,
partials: UDb<SmallStr, Position<ChangeId>>,channels: UDb<SmallStr, T6>,remotes: UDb<SmallStr, T3>,pub(crate) open_channels: RefCell<HashMap<SmallString, ChannelRef<Self>>>,
pub fn check_database(&self) -> DatabaseReport {let mut refs = HashMap::new();self.txn.references(&mut refs, self.internal);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.external);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.inodes);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.revinodes);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.tree);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.revtree);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.revdep);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.dep);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.touched_files);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.rev_touched_files);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.partials);info!("refs = {:?}", refs);self.txn.references(&mut refs, self.channels);info!("refs = {:?}", refs);for x in self.txn.iter(&self.channels, None).unwrap() {let (a, (g, c, r, s, _, _)) = x.unwrap();info!("channel = {:?}", a);self.txn.references(&mut refs, g);info!("refs = {:?}", refs);self.txn.references(&mut refs, c);info!("refs = {:?}", refs);self.txn.references(&mut refs, r);info!("refs = {:?}", refs);self.txn.references(&mut refs, s);info!("refs = {:?}", refs);
pub fn check_database(&self) {let mut refs = std::collections::BTreeMap::new();debug!("check: internal 0x{:x}", self.internal.db);::sanakirja::debug::add_refs(&self.txn, &self.internal, &mut refs).unwrap();debug!("check: external 0x{:x}", self.external.db);::sanakirja::debug::add_refs(&self.txn, &self.external, &mut refs).unwrap();debug!("check: inodes 0x{:x}", self.inodes.db);::sanakirja::debug::add_refs(&self.txn, &self.inodes, &mut refs).unwrap();debug!("check: revinodes 0x{:x}", self.revinodes.db);::sanakirja::debug::add_refs(&self.txn, &self.revinodes, &mut refs).unwrap();debug!("check: tree 0x{:x}", self.tree.db);::sanakirja::debug::add_refs(&self.txn, &self.tree, &mut refs).unwrap();debug!("check: revtree 0x{:x}", self.revtree.db);::sanakirja::debug::add_refs(&self.txn, &self.revtree, &mut refs).unwrap();debug!("check: revdep 0x{:x}", self.revdep.db);::sanakirja::debug::add_refs(&self.txn, &self.revdep, &mut refs).unwrap();debug!("check: dep 0x{:x}", self.dep.db);::sanakirja::debug::add_refs(&self.txn, &self.dep, &mut refs).unwrap();debug!("check: touched_files 0x{:x}", self.touched_files.db);::sanakirja::debug::add_refs(&self.txn, &self.touched_files, &mut refs).unwrap();debug!("check: rev_touched_files 0x{:x}", self.rev_touched_files.db);::sanakirja::debug::add_refs(&self.txn, &self.rev_touched_files, &mut refs).unwrap();debug!("check: partials 0x{:x}", self.partials.db);::sanakirja::debug::add_refs(&self.txn, &self.partials, &mut refs).unwrap();debug!("check: channels 0x{:x}", self.channels.db);::sanakirja::debug::add_refs(&self.txn, &self.channels, &mut refs).unwrap();for x in btree::iter(&self.txn, &self.channels, None).unwrap() {let (name, tup) = x.unwrap();debug!("check: channel name: {:?}", name.as_str());let graph: Db<Vertex<ChangeId>, SerializedEdge> = Db::from_page(tup.0[0].into());let changes: Db<ChangeId, L64> = Db::from_page(tup.0[1].into());let revchanges: UDb<L64, Pair<ChangeId, SerializedMerkle>> = UDb::from_page(tup.0[2].into());let states: UDb<SerializedMerkle, L64> = UDb::from_page(tup.0[3].into());debug!("check: graph 0x{:x}", graph.db);::sanakirja::debug::add_refs(&self.txn, &graph, &mut refs).unwrap();debug!("check: changes 0x{:x}", changes.db);::sanakirja::debug::add_refs(&self.txn, &changes, &mut refs).unwrap();debug!("check: revchanges 0x{:x}", revchanges.db);::sanakirja::debug::add_refs(&self.txn, &revchanges, &mut refs).unwrap();debug!("check: states 0x{:x}", states.db);::sanakirja::debug::add_refs(&self.txn, &states, &mut refs).unwrap();
self.txn.references(&mut refs, self.remotes);info!("refs = {:?}", refs);for x in self.txn.iter(&self.remotes, None).unwrap() {let (a, (u, v, w)) = x.unwrap();info!("remote = {:?}", a);self.txn.references(&mut refs, u);info!("refs = {:?}", refs);self.txn.references(&mut refs, v);info!("refs = {:?}", refs);self.txn.references(&mut refs, w);info!("refs = {:?}", refs);}let stats = self.txn.statistics();let report = DatabaseReport {refs: refs.len(),stats: stats.clone(),};let mut channel_roots: Vec<UnsafeDb> = Vec::new();for x in self.txn.iter(&self.channels, None).unwrap() {let (a, (g, c, r, s, _, _)) = x.unwrap();info!("channel: {:?}", a);unsafe {channel_roots.push(std::mem::transmute(g));channel_roots.push(std::mem::transmute(c));channel_roots.push(std::mem::transmute(r));channel_roots.push(std::mem::transmute(s));}}::sanakirja::debug_(&self.txn, &channel_roots[..], "debug_sanakirja", true);self.txn.check_references(&mut refs);info!("stats = {:?}", stats);let occupied_pages =stats.total_pages - stats.free_pages.len() - stats.bookkeeping_pages.len();for i in 1..(stats.total_pages as u64) {let p = i * 4096;if !refs.contains_key(&p)&& !stats.free_pages.contains(&p)&& !stats.bookkeeping_pages.contains(&p){panic!("does not contain {:?} ({:?})", i, p);}}// check that there is no intersection.for (r, _) in refs.iter() {if stats.free_pages.contains(r) {panic!("referenced page is free: {:?}", r);}if stats.bookkeeping_pages.contains(r) {panic!("referenced page is a bookkeeping page: {:?}", r);}
debug!("check: remotes 0x{:x}", self.remotes.db);::sanakirja::debug::add_refs(&self.txn, &self.remotes, &mut refs).unwrap();for x in btree::iter(&self.txn, &self.remotes, None).unwrap() {let (name, tup) = x.unwrap();debug!("check: remote name: {:?}", name.as_str());let remote: UDb<SmallStr, T3> = UDb::from_page(tup.0[0].into());let rev: UDb<SerializedHash, L64> = UDb::from_page(tup.0[1].into());let states: UDb<SerializedMerkle, L64> = UDb::from_page(tup.0[2].into());debug!("check: remote 0x{:x}", remote.db);::sanakirja::debug::add_refs(&self.txn, &remote, &mut refs).unwrap();debug!("check: rev 0x{:x}", rev.db);::sanakirja::debug::add_refs(&self.txn, &rev, &mut refs).unwrap();debug!("check: states 0x{:x}", states.db);::sanakirja::debug::add_refs(&self.txn, &states, &mut refs).unwrap();
for p in stats.free_pages.iter() {if stats.bookkeeping_pages.contains(p) {panic!("bookkeeping inter free: {:?}", p);}}assert_eq!(1 + refs.len(), occupied_pages);report
::sanakirja::debug::add_free_refs(&self.txn, &mut refs).unwrap();::sanakirja::debug::check_free(&self.txn, &refs);
impl<T: ::sanakirja::Transaction> GraphTxnT for GenericTxn<T> {type Graph = Db<Vertex<ChangeId>, Edge>;
impl<T: ::sanakirja::LoadPage<Error = ::sanakirja::Error>> GraphTxnT for GenericTxn<T> {type Graph = Db<Vertex<ChangeId>, SerializedEdge>;
sanakirja_get!(graph, Vertex<ChangeId>, Edge, GraphError);fn get_external(&self, p: ChangeId) -> Result<Option<Hash>, TxnErr<Self::GraphError>> {
sanakirja_get!(graph, Vertex<ChangeId>, SerializedEdge, GraphError);fn get_external(&self,p: &ChangeId,) -> Result<Option<&SerializedHash>, TxnErr<Self::GraphError>> {debug!("get_external {:?}", p);
fn get_internal(&self, p: Hash) -> Result<Option<ChangeId>, TxnErr<Self::GraphError>> {if let Hash::None = p {Ok(Some(ChangeId::ROOT))} else if let Ok(x) = self.txn.get(&self.internal, p, None) {Ok(x)
fn get_internal(&self, p: &SerializedHash) -> Result<Option<&ChangeId>, TxnErr<Self::GraphError>> {if p.t == HashAlgorithm::None as u8 {Ok(Some(&ChangeId::ROOT))
let edge = Edge {flag: min_flag,dest,introduced_by: ChangeId::ROOT,};if let Ok((cursor, _)) = self.txn.set_cursors(g, Some((key, Some(edge)))) {Ok(Adj {cursor,key,min_flag,max_flag,})} else {Err(TxnErr(SanakirjaError::PristineCorrupt))}
let edge = SerializedEdge::new(min_flag, dest.change, dest.pos, ChangeId::ROOT);let mut cursor = btree::cursor::Cursor::new(&self.txn, g).map_err(TxnErr)?;cursor.set(&self.txn, &key, Some(&edge))?;Ok(Adj {cursor,key,min_flag,max_flag,})
unsafe fn next_graph<T: ::sanakirja::Transaction>(txn: &T,cursor: &mut ::sanakirja::Cursor,) -> Result<Option<(Vertex<ChangeId>, Edge)>, BlockError<SanakirjaError>> {match ::sanakirja::next::<_, Vertex<ChangeId>, Edge>(txn, cursor) {Ok(x) => Ok(x),Err(::sanakirja::CRCError {}) => Err(BlockError::Txn(SanakirjaError::PristineCorrupt)),}}unsafe fn prev_graph<T: ::sanakirja::Transaction>(txn: &T,cursor: &mut ::sanakirja::Cursor,) -> Result<Option<(Vertex<ChangeId>, Edge)>, BlockError<SanakirjaError>> {match ::sanakirja::prev::<_, Vertex<ChangeId>, Edge>(txn, cursor) {Ok(x) => Ok(x),Err(::sanakirja::CRCError {}) => Err(BlockError::Txn(SanakirjaError::PristineCorrupt)),}}
pub fn find_block<T: ::sanakirja::Transaction>(txn: &T,graph: &::sanakirja::Db<Vertex<ChangeId>, Edge>,
pub fn find_block<'a, T: ::sanakirja::LoadPage<Error = ::sanakirja::Error>>(txn: &'a T,graph: &::sanakirja::btree::Db<Vertex<ChangeId>, SerializedEdge>,
let mut k = if let Some((k, _)) = unsafe { next_graph(txn, &mut cursor)? } {
let mut cursor =btree::cursor::Cursor::new(txn, &graph).map_err(|x| BlockError::Txn(x.into()))?;let mut k = if let Some((k, _)) = cursor.set(txn, &key, None).map_err(|x| BlockError::Txn(x.into()))? {k} else if let Some((k, _)) = cursor.prev(txn).map_err(|x| BlockError::Txn(x.into()))? {
debug!("k = {:?}", k);// The only guarantee here is that k is either the first key// >= `key`, or the key just before that. We might need to// rewind by one step if key is strictly larger than the// result (i.e. if `p` is in the middle of the key).
// The only guarantee here is that k is either the first key >=// `key`. We might need to rewind by one step if key is strictly// larger than the result (i.e. if `p` is in the middle of the// key).
pub fn find_block_end<T: ::sanakirja::Transaction>(txn: &T,graph: &::sanakirja::Db<Vertex<ChangeId>, Edge>,
pub fn find_block_end<'a, T: ::sanakirja::LoadPage<Error = ::sanakirja::Error>>(txn: &'a T,graph: &::sanakirja::btree::Db<Vertex<ChangeId>, SerializedEdge>,
debug!(target: "libpijul::find_block_end", "find_block_end {:?}, p.change.0 = {:?}", key, p.change.0);let mut cursor = if let Ok((cursor, _)) = txn.set_cursors(&graph, Some((key, None))) {cursor} else {return Err(BlockError::Txn(SanakirjaError::PristineCorrupt));};let mut k = if let Some((k, _)) = unsafe { next_graph(txn, &mut cursor)? } {
let mut cursor = ::sanakirja::btree::cursor::Cursor::new(txn, graph).map_err(|x| BlockError::Txn(x.into()))?;let mut k = if let Some((k, _)) = cursor.set(txn, &key, None).map_err(|x| BlockError::Txn(x.into()))?{k} else if let Some((k, _)) = cursor.prev(txn).map_err(|x| BlockError::Txn(x.into()))? {
impl<T: ::sanakirja::Transaction> GraphIter for GenericTxn<T> {type GraphCursor = ::sanakirja::Cursor;
impl<T: ::sanakirja::LoadPage<Error = ::sanakirja::Error>> GraphIter for GenericTxn<T> {type GraphCursor = ::sanakirja::btree::cursor::Cursor<Vertex<ChangeId>,SerializedEdge,P<Vertex<ChangeId>, SerializedEdge>,>;
if let Ok((cursor, _)) = self.txn.set_cursors(&g, None) {Ok(cursor)} else {Err(TxnErr(SanakirjaError::PristineCorrupt))}
Ok(::sanakirja::btree::cursor::Cursor::new(&self.txn, &g)?)
) -> Option<Result<(Vertex<ChangeId>, Edge), TxnErr<Self::GraphError>>> {match unsafe { ::sanakirja::next(&self.txn, a) } {
) -> Option<Result<(&'txn Vertex<ChangeId>, &'txn SerializedEdge), TxnErr<Self::GraphError>>>{match a.next(&self.txn) {
// There is a choice here: the datastructure for `revchanges` is// intuitively a list. Moreover, when removing a change, we must// recompute the entire merkle tree after the removed change.//// This seems to indicate that a linked list could be an appropriate// structure (a growable array is excluded because amortised// complexity is not really acceptable here).//// However, we want to be able to answers queries such as "when was// change X introduced?" without having to read the entire database.//// Additionally, even though `SerializedMerkle` has only one// implementation, and is therefore sized in the current// implementation, we can't exclude that other algorithms may be// added, which means that the pages inside linked lists won't even be// randomly-accessible arrays.
pub graph: Db<Vertex<ChangeId>, Edge>,pub changes: Db<ChangeId, u64>,pub revchanges: Db<u64, (ChangeId, Merkle)>,pub states: Db<Merkle, u64>,
pub graph: Db<Vertex<ChangeId>, SerializedEdge>,pub changes: Db<ChangeId, L64>,pub revchanges: UDb<L64, Pair<ChangeId, SerializedMerkle>>,pub states: UDb<SerializedMerkle, L64>,
c: ChangeId,) -> Result<Option<u64>, TxnErr<Self::GraphError>> {if let Ok(x) = self.txn.get(channel, c, None) {Ok(x)} else {Err(TxnErr(SanakirjaError::PristineCorrupt))
c: &ChangeId,) -> Result<Option<&L64>, TxnErr<Self::GraphError>> {match btree::get(&self.txn, channel, c, None) {Ok(Some((k, x))) if k == c => Ok(Some(x)),Ok(x) => {debug!("get_changeset = {:?}", x);Ok(None)},Err(e) => {error!("{:?}", e);Err(TxnErr(SanakirjaError::PristineCorrupt))}
c: u64,) -> Result<Option<(ChangeId, Merkle)>, TxnErr<Self::GraphError>> {if let Ok(x) = self.txn.get(revchanges, c, None) {Ok(x)} else {Err(TxnErr(SanakirjaError::PristineCorrupt))
c: &L64,) -> Result<Option<&Pair<ChangeId, SerializedMerkle>>, TxnErr<Self::GraphError>> {match btree::get(&self.txn, revchanges, c, None) {Ok(Some((k, x))) if k == c => Ok(Some(x)),Ok(_) => Ok(None),Err(e) => {error!("{:?}", e);Err(TxnErr(SanakirjaError::PristineCorrupt))}
if let Ok((cursor, _)) = self.txn.set_cursors(&channel, pos.map(|x| (x, None))) {Ok(Cursor {cursor,txn: self,marker: std::marker::PhantomData,})} else {Err(TxnErr(SanakirjaError::PristineCorrupt))
let mut cursor = btree::cursor::Cursor::new(&self.txn, &channel)?;if let Some(k) = pos {cursor.set(&self.txn, &k, None)?;
if let Ok((cursor, _)) = txn.txn.set_cursors(channel, pos.map(|x| (x, None))) {Ok(Cursor {cursor,txn,marker: std::marker::PhantomData,})} else {Err(TxnErr(SanakirjaError::PristineCorrupt))
let mut cursor = btree::cursor::Cursor::new(&txn.txn, channel)?;if let Some(k) = pos {cursor.set(&txn.txn, &k, None)?;
let cursor = if let Some(pos) = pos {if let Ok((x, _)) = self.txn.set_cursors(channel, Some((pos, None))) {x} else {return Err(TxnErr(SanakirjaError::PristineCorrupt));}} else if let Ok(x) = self.txn.set_cursors_last(channel) {x
let mut cursor = btree::cursor::Cursor::new(&self.txn, channel)?;if let Some(ref pos) = pos {cursor.set(&self.txn, pos, None)?;
) -> Result<Option<(u64, (ChangeId, Merkle))>, TxnErr<SanakirjaError>> {if let Ok(x) = unsafe { ::sanakirja::next(&self.txn, cursor) } {
) -> Result<Option<(&L64, &Pair<ChangeId, SerializedMerkle>)>, TxnErr<SanakirjaError>> {if let Ok(x) = cursor.next(&self.txn) {
) -> Result<Option<(u64, (ChangeId, Merkle))>, TxnErr<SanakirjaError>> {if let Ok(x) = unsafe { ::sanakirja::prev(&self.txn, cursor) } {
) -> Result<Option<(&L64, &Pair<ChangeId, SerializedMerkle>)>, TxnErr<SanakirjaError>> {if let Ok(x) = cursor.prev(&self.txn) {
m: Merkle,) -> Result<Option<u64>, TxnErr<Self::GraphError>> {Ok(self.txn.get(channel, m, None)?)
m: &SerializedMerkle,) -> Result<Option<L64>, TxnErr<Self::GraphError>> {match btree::get(&self.txn, channel, m, None)? {Some((k, v)) if k == m => Ok(Some(*v)),_ => Ok(None)}
type Tree = Db<UnsafePathId, Inode>;sanakirja_table_get!(tree,PathId,Inode,TreeError,(UnsafePathId::from_fileid(key), value),);sanakirja_iter!(tree,OwnedPathId,Inode,if let Some((ref k, ref v)) = pos {info!("tree iter {:?} {:?}", k, v);Some((UnsafePathId::from_fileid(k.as_file_id()), *v))} else {None},map(|(k, v): (UnsafePathId, Inode)| (unsafe { k.to_fileid().to_owned() }, v)));sanakirja_iter!(revtree,Inode,OwnedPathId,if let Some((ref k, ref v)) = pos {let v = if let Some(ref v) = *v {Some(UnsafePathId::from_fileid(v.as_file_id()))} else {None};Some((*k, v))} else {None},map(|(k, v): (Inode, UnsafePathId)| (k, unsafe { v.to_fileid().to_owned() })));
type Tree = UDb<PathId, Inode>;sanakirja_table_get!(tree, PathId, Inode, TreeError,);type TreeCursor =::sanakirja::btree::cursor::Cursor<PathId, Inode, UP<PathId, Inode>>;sanakirja_iter!(tree, PathId, Inode,);type RevtreeCursor =::sanakirja::btree::cursor::Cursor<Inode, PathId, UP<Inode, PathId>>;sanakirja_iter!(revtree, Inode, PathId);
type Revtree = Db<Inode, UnsafePathId>;sanakirja_table_get!(revtree,Inode,PathId,TreeError,(key,if let Some(value) = value {Some(UnsafePathId::from_fileid(value))} else {None}),map(|value| unsafe { value.to_fileid() }));
type Revtree = UDb<Inode, PathId>;sanakirja_table_get!(revtree, Inode, PathId, TreeError,);
if let Some((ref k, ref v)) = pos {Some((UnsafeSmallStr::from_small_str(k.as_small_str()), *v))} else {None},map(|(k, v): (UnsafeSmallStr, Position<ChangeId>)| (unsafe { k.to_small_str().to_owned() },v)));
UP<SmallStr, Position<ChangeId>>,>;sanakirja_cursor!(partials, SmallStr, Position<ChangeId>,);type InodesCursor =::sanakirja::btree::cursor::Cursor<Inode, Position<ChangeId>, P<Inode, Position<ChangeId>>>;
if let Some((channel, changes, revchanges, states, counter, last_modified)) = self.txn.get(&self.channels,UnsafeSmallStr::from_small_str(name.as_small_str()),None,)? {debug!("unsafe_load_channel: found {:?} {:?}", changes, revchanges);Ok(Some(Channel {graph: channel,changes,revchanges,apply_counter: counter,states,name: name.clone(),last_modified,}))} else {debug!("unsafe_load_channel: not found");Ok(None)
match btree::get(&self.txn, &self.channels, &name, None)? {Some((name_, tup)) => {assert_eq!(name_, name.as_ref());debug!("load_channel: {:?} {:?}", name, tup);Ok(Some(Channel {graph: Db::from_page(tup.0[0].into()),changes: Db::from_page(tup.0[1].into()),revchanges: UDb::from_page(tup.0[2].into()),states: UDb::from_page(tup.0[3].into()),apply_counter: tup.0[4].into(),last_modified: tup.0[5].into(),name,}))}_ => {debug!("unsafe_load_channel: not found");Ok(None)}
if let Some(remote) = self.txn.get(&self.remotes,UnsafeSmallStr::from_small_str(name.as_small_str()),None,)? {let r = RemoteRef {db: Rc::new(RefCell::new(Remote {remote: remote.0,rev: remote.1,states: remote.2,})),name: name.clone(),};Ok(Some(v.insert(r).clone()))} else {return Ok(None);
match btree::get(&self.txn, &self.remotes, &name, None)? {Some((name_, remote)) if name.as_ref() == name_ => {debug!("load_remote: {:?} {:?}", name_, remote);let r = Remote {remote: UDb::from_page(remote.0[0].into()),rev: UDb::from_page(remote.0[1].into()),states: UDb::from_page(remote.0[2].into()),};for x in btree::iter(&self.txn, &r.remote, None).unwrap() {debug!("remote -> {:?}", x);}for x in btree::iter(&self.txn, &r.rev, None).unwrap() {debug!("rev -> {:?}", x);}for x in btree::iter(&self.txn, &r.states, None).unwrap() {debug!("states -> {:?}", x);}for x in self.iter_remote(&r.remote, 0).unwrap() {debug!("ITER {:?}", x);}let r = RemoteRef {db: Rc::new(RefCell::new(r)),name: name.clone(),};Ok(Some(v.insert(r).clone()))}_ => return Ok(None)
type Channels = Db<UnsafeSmallStr, (u64, u64, u64, u64, u64, u64)>;sanakirja_cursor!(channels,SmallString,(u64, u64, u64, u64, u64, u64),if let Some((ref k, ref v)) = pos {Some((UnsafeSmallStr::from_small_str(k.as_small_str()), *v))} else {None},map(|(k, v): (UnsafeSmallStr, (u64, u64, u64, u64, u64, u64))| (unsafe { k.to_small_str().to_owned() },v)));
type Channels = UDb<SmallStr, T6>;type ChannelsCursor = ::sanakirja::btree::cursor::Cursor<SmallStr, T6, UP<SmallStr, T6>>;sanakirja_cursor!(channels, SmallStr, T6,);
let name = UnsafeSmallStr::from_small_str(name.as_small_str());Ok(ChannelIterator {cursor: self.txn.set_cursors(&self.channels, Some((name, None)))?.0,txn: self,})
let mut cursor = btree::cursor::Cursor::new(&self.txn, &self.channels)?;cursor.set(&self.txn, &name, None)?;Ok(ChannelIterator { cursor, txn: self })
type Remotes = Db<UnsafeSmallStr, (u64, u64, u64)>;sanakirja_cursor!(remotes,SmallString,(u64, u64, u64),if let Some((ref k, ref v)) = pos {Some((UnsafeSmallStr::from_small_str(k.as_small_str()), *v))} else {None},map(|(k, v): (UnsafeSmallStr, (u64, u64, u64))| (unsafe { k.to_small_str().to_owned() },v)));
type Remotes = UDb<SmallStr, T3>;type RemotesCursor = ::sanakirja::btree::cursor::Cursor<SmallStr, T3, UP<SmallStr, T3>>;sanakirja_cursor!(remotes, SmallStr, T3);
let name = UnsafeSmallStr::from_small_str(name.as_small_str());Ok(RemotesIterator {cursor: self.txn.set_cursors(&self.remotes, Some((name, None)))?.0,txn: self,})
let mut cursor = btree::cursor::Cursor::new(&self.txn, &self.remotes)?;cursor.set(&self.txn, &name, None)?;Ok(RemotesIterator { cursor, txn: self })
type Remote = Db<u64, (Hash, Merkle)>;type Revremote = Db<Hash, u64>;type Remotestates = Db<Merkle, u64>;sanakirja_cursor!(remote, u64, (Hash, Merkle));sanakirja_rev_cursor!(remote, u64, (Hash, Merkle));
type Remote = UDb<L64, Pair<SerializedHash, SerializedMerkle>>;type Revremote = UDb<SerializedHash, L64>;type Remotestates = UDb<SerializedMerkle, L64>;type RemoteCursor = ::sanakirja::btree::cursor::Cursor<L64,Pair<SerializedHash, SerializedMerkle>,UP<L64, Pair<SerializedHash, SerializedMerkle>>,>;sanakirja_cursor!(remote, L64, Pair<SerializedHash, SerializedMerkle>);sanakirja_rev_cursor!(remote, L64, Pair<SerializedHash, SerializedMerkle>);
if let Some(remote) = self.txn.get(&self.remotes,UnsafeSmallStr::from_small_str(name.as_small_str()),None,)? {let r = RemoteRef {db: Rc::new(RefCell::new(Remote {remote: remote.0,rev: remote.1,states: remote.2,})),name: name.clone(),};v.insert(r);} else {return Ok(None);
match btree::get(&self.txn, &self.remotes, &name, None)? {Some((name_, remote)) if name_ == name.as_ref() => {let r = RemoteRef {db: Rc::new(RefCell::new(Remote {remote: UDb::from_page(remote.0[0].into()),rev: UDb::from_page(remote.0[1].into()),states: UDb::from_page(remote.0[2].into()),})),name: name.clone(),};v.insert(r);}_ => return Ok(None),
) -> Result<Option<(u64, (Hash, Merkle))>, TxnErr<Self::GraphError>> {Ok(self.txn.rev_iter(remote, None)?.next().transpose()?)
) -> Result<Option<(u64, &Pair<SerializedHash, SerializedMerkle>)>, TxnErr<Self::GraphError>>{if let Some(x) = btree::rev_iter(&self.txn, remote, None)?.next() {let (&k, v) = x?;Ok(Some((k.into(), v)))} else {Ok(None)}
) -> Result<Option<(u64, (Hash, Merkle))>, TxnErr<Self::GraphError>> {for x in self.txn.iter(remote, Some((n, None)))? {let (k, m) = x?;
) -> Result<Option<(u64, &Pair<SerializedHash, SerializedMerkle>)>, TxnErr<Self::GraphError>>{let n = n.into();for x in btree::iter(&self.txn, remote, Some((&n, None)))? {let (&k, m) = x?;
sanakirja_put_del!(internal, Hash, ChangeId, GraphError);sanakirja_put_del!(external, ChangeId, Hash, GraphError);
sanakirja_put_del!(internal, SerializedHash, ChangeId, GraphError);sanakirja_put_del!(external, ChangeId, SerializedHash, GraphError);
assert!(chi.introduced_by != ChangeId::ROOT || chi.flag.contains(EdgeFlags::PSEUDO));if chi.flag.contains(EdgeFlags::PARENT | EdgeFlags::BLOCK) {
assert!(chi.introduced_by() != ChangeId::ROOT || chi.flag().contains(EdgeFlags::PSEUDO));if chi.flag().contains(EdgeFlags::PARENT | EdgeFlags::BLOCK) {
for i in self.txn.iter(&channel.changes, None).unwrap() {debug!("changes {:?}", i);}let m = if let Some(x) = self.txn.rev_iter(&channel.revchanges, None)?.next() {(x?.1).1
let m = if let Some(x) = btree::rev_iter(&self.txn, &channel.revchanges, None)?.next() {(&(x?.1).b).into()
.txn.put(&mut self.rng, &mut channel.revchanges, t, (p, m))?);Ok(Some(m))} else {Ok(None)
.get_revchangeset(&channel.revchanges, &t.into())?.is_none());assert!(btree::put(&mut self.txn,&mut channel.changes,&p,&t.into())?);assert!(btree::put(&mut self.txn,&mut channel.revchanges,&t.into(),&Pair { a: p, b: m.into() })?);Ok(Some(m.into()))
for x in self.txn.iter(&channel.revchanges, Some((t, None)))? {let (t_, (p, _)) = x?;if t_ >= t {repl.push((t_, p))
let tl = t.into();for x in btree::iter(&self.txn, &channel.revchanges, Some((&tl, None)))? {let (t_, p) = x?;if *t_ >= tl {repl.push((*t_, p.a))
for x in self.txn.rev_iter(&channel.revchanges, Some((t, None)))? {let (t_, (_, m_)) = x?;if t_ < t {m = m_;
for x in btree::rev_iter(&self.txn, &channel.revchanges, Some((&tl, None)))? {let (t_, mm) = x?;if t_ < &tl {m = (&mm.b).into();
self.txn.del(&mut self.rng, &mut channel.revchanges, *t_, None)?;if *t_ > t {m = m.next(&self.get_external(*p)?.unwrap());self.txn.put(&mut self.rng, &mut channel.revchanges, *t_, (*p, m))?;
btree::del(&mut self.txn, &mut channel.revchanges, t_, None)?;if *t_ > tl {m = m.next(&self.get_external(p)?.unwrap().into());btree::put(&mut self.txn,&mut channel.revchanges,t_,&Pair { a: *p, b: m.into() },)?;
sanakirja_put_del!(tree,PathId,Inode,TreeError,UnsafePathId::from_fileid(k),v);sanakirja_put_del!(revtree,Inode,PathId,TreeError,k,UnsafePathId::from_fileid(v));
sanakirja_put_del!(tree, PathId, Inode, TreeError,);sanakirja_put_del!(revtree, Inode, PathId, TreeError,);
self.txn.put(&mut self.rng, &mut remote.remote, k, v)?;self.txn.put(&mut self.rng, &mut remote.states, v.1, k)?;Ok(self.txn.put(&mut self.rng, &mut remote.rev, v.0, k)?)
let h = (&v.0).into();let m: SerializedMerkle = (&v.1).into();btree::put(&mut self.txn,&mut remote.remote,&k.into(),&Pair { a: h, b: m.clone() },)?;btree::put(&mut self.txn, &mut remote.states, &m, &k.into())?;Ok(btree::put(&mut self.txn, &mut remote.rev, &h, &k.into())?)
if let Some((h, m)) = self.txn.get(&remote.remote, k, None)? {self.txn.del(&mut self.rng, &mut remote.rev, h, None)?;self.txn.del(&mut self.rng, &mut remote.states, m, None)?;Ok(self.txn.del(&mut self.rng, &mut remote.remote, k, None)?)} else {Ok(false)
let k = k.into();match btree::get(&self.txn, &remote.remote, &k, None)? {Some((k0, p)) if k0 == &k => {debug!("del_remote {:?} {:?}", k0, p);let p = p.clone();btree::del(&mut self.txn, &mut remote.rev, &p.a, None)?;btree::del(&mut self.txn, &mut remote.states, &p.b, None)?;Ok(btree::del(&mut self.txn,&mut remote.remote,&k.into(),None,)?)}x => {debug!("not found, {:?}", x);Ok(false)}
let r = if let Some((graph,changes,revchanges,states,apply_counter,last_modified,)) = self.txn.get(&self.channels,UnsafeSmallStr::from_small_str(name.as_small_str()),None,)? {ChannelRef {r: Rc::new(RefCell::new(Channel {graph,changes,revchanges,states,apply_counter,name: name.clone(),last_modified,})),}} else {let br = ChannelRef {r: Rc::new(RefCell::new(Channel {graph: self.txn.create_db()?,changes: self.txn.create_db()?,revchanges: self.txn.create_db()?,states: self.txn.create_db()?,apply_counter: 0,name: name.clone(),last_modified: 0,})),
let r =match btree::get(&self.txn, &self.channels, &name, None)? {Some((name_, b)) => {assert_eq!(name_, name.as_ref());ChannelRef {r: Rc::new(RefCell::new(Channel {graph: Db::from_page(b.0[0].into()),changes: Db::from_page(b.0[1].into()),revchanges: UDb::from_page(b.0[2].into()),states: UDb::from_page(b.0[3].into()),apply_counter: b.0[4].into(),name: name.clone(),last_modified: b.0[5].into(),})),}}_ => {let br = ChannelRef {r: Rc::new(RefCell::new(Channel {graph: btree::create_db_(&mut self.txn)?,changes: btree::create_db_(&mut self.txn)?,revchanges: btree::create_db_(&mut self.txn)?,states: btree::create_db_(&mut self.txn)?,apply_counter: 0,name: name.clone(),last_modified: 0,})),};commit = Some(br.clone());br}
let br = ChannelRef {r: Rc::new(RefCell::new(Channel {graph: self.txn.fork(&mut self.rng, &channel.graph).map_err(|e| ForkError::Txn(e.into()))?,changes: self.txn.fork(&mut self.rng, &channel.changes).map_err(|e| ForkError::Txn(e.into()))?,revchanges: self.txn.fork(&mut self.rng, &channel.revchanges).map_err(|e| ForkError::Txn(e.into()))?,states: self.txn.fork(&mut self.rng, &channel.states).map_err(|e| ForkError::Txn(e.into()))?,name: name.clone(),apply_counter: channel.apply_counter,last_modified: channel.last_modified,})),};self.open_channels.borrow_mut().insert(name, br.clone());Ok(br)} else {Err(super::ForkError::ChannelNameExists(new_name.to_string()))
Some((name_, _)) if name_ == name.as_ref() =>Err(super::ForkError::ChannelNameExists(new_name.to_string())),_ => {let br = ChannelRef {r: Rc::new(RefCell::new(Channel {graph: btree::fork_db(&mut self.txn, &channel.graph).map_err(|e| ForkError::Txn(e.into()))?,changes: btree::fork_db(&mut self.txn, &channel.changes).map_err(|e| ForkError::Txn(e.into()))?,revchanges: btree::fork_db(&mut self.txn, &channel.revchanges).map_err(|e| ForkError::Txn(e.into()))?,states: btree::fork_db(&mut self.txn, &channel.states).map_err(|e| ForkError::Txn(e.into()))?,name: name.clone(),apply_counter: channel.apply_counter,last_modified: channel.last_modified,})),};self.open_channels.borrow_mut().insert(name, br.clone());Ok(br)}
let mut dbs_channels: ::sanakirja::Db<UnsafeSmallStr, (u64, u64, u64, u64, u64, u64)> =unsafe { std::mem::transmute(self.channels) };self.txn.del(&mut self.rng,&mut dbs_channels,UnsafeSmallStr::from_small_str(channel.borrow().name.as_small_str()),
Some((name_, _)) if name_ == name.as_ref() =>Err(super::ForkError::ChannelNameExists(new_name.to_string())),_ => {btree::del(&mut self.txn,&mut self.channels,&channel.borrow().name,
.map_err(|e| ForkError::Txn(e.into()))?;self.channels = unsafe { std::mem::transmute(dbs_channels) };std::mem::drop(
.map_err(|e| ForkError::Txn(e.into()))?;std::mem::drop(self.open_channels.borrow_mut().remove(&channel.borrow().name).unwrap(),);std::cell::RefCell::borrow_mut(&std::rc::Rc::get_mut(&mut channel.r).unwrap()).name =name.clone();
.remove(&channel.borrow().name).unwrap(),);std::cell::RefCell::borrow_mut(&std::rc::Rc::get_mut(&mut channel.r).unwrap()).name =name.clone();self.open_channels.borrow_mut().insert(name, channel.clone());Ok(())} else {Err(ForkError::ChannelNameExists(new_name.to_string()))
.insert(name, channel.clone());Ok(())}
let r = if let Some(remote) = self.txn.get(&self.remotes,UnsafeSmallStr::from_small_str(name.as_small_str()),None,)? {RemoteRef {db: Rc::new(RefCell::new(Remote {remote: remote.0,rev: remote.1,states: remote.2,})),name: name.clone(),}} else {let br = RemoteRef {db: Rc::new(RefCell::new(Remote {remote: self.txn.create_db()?,rev: self.txn.create_db()?,states: self.txn.create_db()?,})),name: name.clone(),
let r =match btree::get(&self.txn, &self.remotes, &name, None)? {Some((name_, remote)) if name_ == name.as_ref() => {RemoteRef {db: Rc::new(RefCell::new(Remote {remote: UDb::from_page(remote.0[0].into()),rev: UDb::from_page(remote.0[1].into()),states: UDb::from_page(remote.0[2].into()),})),name: name.clone(),}}_ => {let br = RemoteRef {db: Rc::new(RefCell::new(Remote {remote: btree::create_db_(&mut self.txn)?,rev: btree::create_db_(&mut self.txn)?,states: btree::create_db_(&mut self.txn)?,})),name: name.clone(),};commit = Some(br.clone());br}
self.txn.set_root(Root::Tree as usize, self.tree);self.txn.set_root(Root::RevTree as usize, self.revtree);self.txn.set_root(Root::Inodes as usize, self.inodes);self.txn.set_root(Root::RevInodes as usize, self.revinodes);self.txn.set_root(Root::Internal as usize, self.internal);self.txn.set_root(Root::External as usize, self.external);self.txn.set_root(Root::RevDep as usize, self.revdep);self.txn.set_root(Root::Channels as usize, self.channels);self.txn.set_root(Root::Remotes as usize, self.remotes);
self.txn.set_root(Root::Tree as usize, self.tree.db);self.txn.set_root(Root::RevTree as usize, self.revtree.db);self.txn.set_root(Root::Inodes as usize, self.inodes.db);self.txn.set_root(Root::RevInodes as usize, self.revinodes.db);self.txn.set_root(Root::Internal as usize, self.internal.db);self.txn.set_root(Root::External as usize, self.external.db);self.txn.set_root(Root::RevDep as usize, self.revdep.db);self.txn.set_root(Root::Channels as usize, self.channels.db);self.txn.set_root(Root::Remotes as usize, self.remotes.db);
.set_root(Root::RevTouchedFiles as usize, self.rev_touched_files);self.txn.set_root(Root::Partials as usize, self.partials);
.set_root(Root::RevTouchedFiles as usize, self.rev_touched_files.db);self.txn.set_root(Root::Partials as usize, self.partials.db);
if let Some((channel, changes, revchanges, states, counter, last_modified)) = self.txn.get(&self.channels,UnsafeSmallStr::from_small_str(name.as_small_str()),None,)? {Ok(Some(Channel {graph: channel,changes,revchanges,states,apply_counter: counter,name,last_modified,}))} else {Ok(None)
match btree::get(&self.txn, &self.channels, &name, None)? {Some((name_, c)) => {assert_eq!(name.as_ref(), name_);debug!("load_const_channel = {:?} {:?}", name_ ,c);Ok(Some(Channel {graph: Db::from_page(c.0[0].into()),changes: Db::from_page(c.0[1].into()),revchanges: UDb::from_page(c.0[2].into()),states: UDb::from_page(c.0[3].into()),apply_counter: c.0[4].into(),last_modified: c.0[5].into(),name,}))}_ => Ok(None)
let mut dbs_channels: ::sanakirja::Db<UnsafeSmallStr, (u64, u64, u64, u64, u64, u64)> =unsafe { std::mem::transmute(self.channels) };debug!("Commit_channel, dbs_channels = {:?}", dbs_channels);self.txn.del(&mut self.rng,&mut dbs_channels,UnsafeSmallStr::from_small_str(channel.name.as_small_str()),
debug!("Commit_channel, dbs_channels = {:?}", self.channels);btree::del(&mut self.txn,&mut self.channels,&channel.name,
debug!("Commit_channel, dbs_channels = {:?}", dbs_channels);self.channels = unsafe { std::mem::transmute(dbs_channels) };self.txn.put(&mut self.rng,
let t6 = T6([channel.graph.db.into(),channel.changes.db.into(),channel.revchanges.db.into(),channel.states.db.into(),channel.apply_counter.into(),channel.last_modified.into(),]);debug!("t6 = {:?}", t6);btree::put(&mut self.txn,
let mut dbs_remotes: ::sanakirja::Db<UnsafeSmallStr, (u64, u64, u64)> =unsafe { std::mem::transmute(self.remotes) };debug!("Commit_remote, dbs_remotes = {:?}", dbs_remotes);self.txn.del(&mut self.rng,&mut dbs_remotes,UnsafeSmallStr::from_small_str(remote.name.as_small_str()),
btree::del(&mut self.txn,&mut self.remotes,&remote.name,
const CHANGE_ID_SIZE: usize = 8;impl Representable for ChangeId {fn alignment() -> Alignment {Alignment::B8}fn onpage_size(&self) -> u16 {CHANGE_ID_SIZE as u16}unsafe fn write_value(&self, p: *mut u8) {LittleEndian::write_u64(std::slice::from_raw_parts_mut(p, 8), self.0)}unsafe fn read_value(p: *const u8) -> Self {ChangeId(LittleEndian::read_u64(std::slice::from_raw_parts(p, 8)))}unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {self.0.cmp(&x.0)}type PageOffsets = std::iter::Empty<u64>;fn page_offsets(&self) -> Self::PageOffsets {std::iter::empty()}}
direct_repr!(L64);
impl Representable for Vertex<ChangeId> {fn alignment() -> Alignment {Alignment::B1}fn onpage_size(&self) -> u16 {VERTEX_SIZE as u16}unsafe fn write_value(&self, p: *mut u8) {let p = std::slice::from_raw_parts_mut(p, VERTEX_SIZE);LittleEndian::write_u64(p, self.change.0);LittleEndian::write_u64(&mut p[CHANGE_ID_SIZE..], self.start.0);LittleEndian::write_u64(&mut p[CHANGE_ID_SIZE + 8..], self.end.0);}unsafe fn read_value(p: *const u8) -> Self {let p = std::slice::from_raw_parts(p, VERTEX_SIZE);let change = LittleEndian::read_u64(p);let start = LittleEndian::read_u64(&p[CHANGE_ID_SIZE..]);let end = LittleEndian::read_u64(&p[CHANGE_ID_SIZE + 8..]);Vertex {change: ChangeId(change),start: ChangePosition(start),end: ChangePosition(end),}}unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {self.cmp(&x)}type PageOffsets = std::iter::Empty<u64>;fn page_offsets(&self) -> Self::PageOffsets {std::iter::empty()}}
direct_repr!(Vertex<ChangeId>);direct_repr!(Position<ChangeId>);
impl Representable for Position<ChangeId> {fn alignment() -> Alignment {Alignment::B1}fn onpage_size(&self) -> u16 {(CHANGE_ID_SIZE + 8) as u16}unsafe fn write_value(&self, p: *mut u8) {let p = std::slice::from_raw_parts_mut(p, CHANGE_ID_SIZE + 8);LittleEndian::write_u64(p, self.change.0);LittleEndian::write_u64(&mut p[CHANGE_ID_SIZE..], self.pos.0);}unsafe fn read_value(p: *const u8) -> Self {let p = std::slice::from_raw_parts(p, CHANGE_ID_SIZE + 8);let change = LittleEndian::read_u64(p);let pos = LittleEndian::read_u64(&p[CHANGE_ID_SIZE..]);Position {change: ChangeId(change),pos: ChangePosition(pos),}}unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {self.cmp(&x)
direct_repr!(SerializedEdge);impl Storable for PathId {fn compare<T>(&self, _: &T, x: &Self) -> std::cmp::Ordering {self.cmp(x)
unsafe fn write_value(&self, p: *mut u8) {let s = std::slice::from_raw_parts_mut(p, 25);s[0] = (*self).flag.bits();LittleEndian::write_u64(&mut s[1..], (*self).dest.change.0);LittleEndian::write_u64(&mut s[9..], (*self).dest.pos.0);LittleEndian::write_u64(&mut s[17..], (*self).introduced_by.0);
unsafe fn onpage_size(p: *const u8) -> usize {let len = *(p.add(8)) as usize;9 + len
unsafe fn read_value(p: *const u8) -> Self {let s = std::slice::from_raw_parts(p, 25);Edge {flag: if let Some(b) = EdgeFlags::from_bits(s[0]) {b} else {panic!("read_value, edge = {:?}", s);},dest: Position {change: ChangeId(LittleEndian::read_u64(&s[1..])),pos: ChangePosition(LittleEndian::read_u64(&s[9..])),},introduced_by: ChangeId(LittleEndian::read_u64(&s[17..])),}
unsafe fn from_raw_ptr<'a, T>(_: &T, p: *const u8) -> &'a Self {path_id_from_raw_ptr(p)
unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {let a: &Edge = self;let b: &Edge = &x;a.cmp(b)
unsafe fn write_to_page(&self, p: *mut u8) {*(p as *mut u64) = (self.parent_inode.0).0;self.basename.write_to_page(p.add(8))
/// An internal "unsafe" version of a [`pristine::PathId`], used to/// circumvent the absence of associated type constructors in Rust/// (else this would be borrow on a table).#[derive(Clone, Copy, Debug)]pub struct UnsafePathId {parent_inode: Inode,basename: UnsafeSmallStr,
unsafe fn path_id_from_raw_ptr<'a>(p: *const u8) -> &'a PathId {let len = *(p.add(8)) as usize;std::mem::transmute(std::slice::from_raw_parts(p, 1 + len as usize))
impl UnsafePathId {pub fn from_fileid(f: PathId) -> UnsafePathId {UnsafePathId {parent_inode: f.parent_inode,basename: UnsafeSmallStr::from_small_str(f.basename),}}pub unsafe fn to_fileid<'a>(&self) -> PathId<'a> {PathId {parent_inode: self.parent_inode,basename: self.basename.to_small_str(),}
#[test]fn pathid_repr() {let o = OwnedPathId {parent_inode: Inode::ROOT,basename: SmallString::from_str("blablabla")};let mut x = vec![0u8; 200];unsafe {o.write_to_page(x.as_mut_ptr());let p = path_id_from_raw_ptr(x.as_ptr());assert_eq!(p.basename.as_str(), "blablabla");assert_eq!(p.parent_inode, Inode::ROOT);
impl Representable for UnsafePathId {fn alignment() -> Alignment {Alignment::B1}fn onpage_size(&self) -> u16 {INODE_SIZE + self.basename.onpage_size()}unsafe fn write_value(&self, p: *mut u8) {self.parent_inode.write_value(p);self.basename.write_value(p.offset(INODE_SIZE as isize));}unsafe fn read_value(p: *const u8) -> Self {UnsafePathId {parent_inode: Inode::read_value(p),basename: UnsafeSmallStr::read_value(p.offset(INODE_SIZE as isize)),}}unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {let a: PathId = self.to_fileid();let b: PathId = x.to_fileid();a.cmp(&b)}type PageOffsets = std::iter::Empty<u64>;fn page_offsets(&self) -> Self::PageOffsets {std::iter::empty()}}
const INODE_SIZE: u16 = 8;impl Representable for Inode {fn alignment() -> Alignment {Alignment::B8}fn onpage_size(&self) -> u16 {INODE_SIZE}unsafe fn write_value(&self, p: *mut u8) {LittleEndian::write_u64(std::slice::from_raw_parts_mut(p, 8), self.0)}unsafe fn read_value(p: *const u8) -> Self {Inode(LittleEndian::read_u64(std::slice::from_raw_parts(p, 8)))}unsafe fn cmp_value<T>(&self, _: &T, x: Self) -> std::cmp::Ordering {self.0.cmp(&x.0)}type PageOffsets = std::iter::Empty<u64>;fn page_offsets(&self) -> Self::PageOffsets {std::iter::empty()}}
fn onpage_size(&self) -> u16 {1 + (match *self {Hash::Blake3(_) => 32,Hash::None => 0,})}unsafe fn write_value(&self, p: *mut u8) {match *self {Hash::Blake3(q) => {*p = HashAlgorithm::Blake3 as u8;std::ptr::copy(q.as_ptr(), p.offset(1), 32)}Hash::None => *p = HashAlgorithm::None as u8,}
impl<A: Storable, B: Storable> Storable for Pair<A, B> {type PageReferences = core::iter::Chain<A::PageReferences, B::PageReferences>;fn page_references(&self) -> Self::PageReferences {self.a.page_references().chain(self.b.page_references())
unsafe fn read_value(p: *const u8) -> Self {assert!(*p <= HashAlgorithm::Blake3 as u8);match std::mem::transmute(*p) {HashAlgorithm::Blake3 => {let mut h = [0; BLAKE3_BYTES];std::ptr::copy(p.offset(1), h.as_mut_ptr(), BLAKE3_BYTES);Hash::Blake3(h)}HashAlgorithm::None => Hash::None,
fn compare<T: LoadPage>(&self, t: &T, b: &Self) -> core::cmp::Ordering {match self.a.compare(t, &b.a) {core::cmp::Ordering::Equal => self.b.compare(t, &b.b),ord => ord
unsafe fn write_value(&self, p: *mut u8) {match *self {Merkle::Ed25519(q) => {*p = MerkleAlgorithm::Ed25519 as u8;assert_eq!(*p, 1);let q = q.compress();let q = q.as_bytes();std::ptr::copy(q.as_ptr(), p.offset(1), 32);}}}unsafe fn read_value(p: *const u8) -> Self {assert_eq!(*p, MerkleAlgorithm::Ed25519 as u8);let slice = std::slice::from_raw_parts(p.offset(1), 32);Merkle::Ed25519(curve25519_dalek::edwards::CompressedEdwardsY::from_slice(slice).decompress().unwrap(),)
unsafe fn onpage_size(p: *const u8) -> usize {let a = A::onpage_size(p);let b_off = (a + (B::ALIGN - 1)) & !(B::ALIGN - 1);let b_size = B::onpage_size(p.add(b_off));(b_off + b_size + (Self::ALIGN - 1)) & !(Self::ALIGN - 1)
type PageOffsets = std::iter::Empty<u64>;fn page_offsets(&self) -> Self::PageOffsets {std::iter::empty()
unsafe fn write_to_page(&self, p: *mut u8) {self.a.write_to_page(p);let off = (self.a.size() + (B::ALIGN - 1)) & !(B::ALIGN - 1);self.b.write_to_page(p.add(off));
direct_repr!(T3);direct_repr!(T6);
#[cfg(feature = "dump")]pub mod channel_dump;
// #[cfg(feature = "dump")]// pub mod channel_dump;#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]pub struct L64(pub u64);impl From<usize> for L64 {fn from(u: usize) -> Self {L64((u as u64).to_le())}}impl From<u64> for L64 {fn from(u: u64) -> Self {L64(u.to_le())}}impl From<L64> for u64 {fn from(u: L64) -> Self {u64::from_le(u.0)}}impl From<L64> for usize {fn from(u: L64) -> Self {u64::from_le(u.0) as usize}}impl L64 {pub fn as_u64(&self) -> u64 {u64::from_le(self.0)}pub fn as_usize(&self) -> usize {u64::from_le(self.0) as usize}}impl std::fmt::Display for L64 {fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {self.0.fmt(fmt)}}impl Ord for L64 {fn cmp(&self, x: &Self) -> std::cmp::Ordering {u64::from_le(self.0).cmp(&u64::from_le(x.0))}}impl PartialOrd for L64 {fn partial_cmp(&self, x: &Self) -> Option<std::cmp::Ordering> {Some(u64::from_le(self.0).cmp(&u64::from_le(x.0)))}}impl std::ops::Add<L64> for L64 {type Output = Self;fn add(self, x: L64) -> L64 {L64((u64::from_le(self.0) + u64::from_le(x.0)).to_le())}}impl std::ops::Add<usize> for L64 {type Output = Self;fn add(self, x: usize) -> L64 {L64((u64::from_le(self.0) + x as u64).to_le())}}impl std::ops::SubAssign<usize> for L64 {fn sub_assign(&mut self, x: usize) {self.0 = ((u64::from_le(self.0)) - x as u64).to_le()}}impl L64 {pub fn from_slice_le(s: &[u8]) -> Self {let mut u = 0u64;assert!(s.len() >= 8);unsafe {std::ptr::copy_nonoverlapping(s.as_ptr(), &mut u as *mut u64 as *mut u8, 8)}L64(u)}pub fn to_slice_le(&self, s: &mut [u8]) {assert!(s.len() >= 8);unsafe {std::ptr::copy_nonoverlapping(&self.0 as *const u64 as *const u8, s.as_mut_ptr(), 8)}}}#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]#[repr(C)]pub struct T3([L64; 3]);#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]#[repr(C)]pub struct T6([L64; 6]);#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]#[repr(C)]pub struct Pair<A, B> {pub a: A,pub b: B,}
from: u64,) -> Result<Cursor<T, &'txn T, T::RevchangesetCursor, u64, (ChangeId, Merkle)>, TxnErr<T::GraphError>>
from: L64,) -> Result<Cursor<T, &'txn T, T::RevchangesetCursor, L64, Pair<ChangeId, SerializedMerkle>>, TxnErr<T::GraphError>>
}pub(crate) fn changeid_log_ref<T: ChannelTxnT, RT: std::ops::Deref<Target = T>>(txn: RT,channel: &T::Channel,from: u64,) -> Result<Cursor<T, RT, T::RevchangesetCursor, u64, (ChangeId, Merkle)>, TxnErr<T::GraphError>> {let c = txn.rev_changes(&channel);Ok(T::cursor_revchangeset_ref(txn, c, Some(from))?)
while txn.get_external(p)?.is_some() {p = ChangeId(rand::thread_rng().gen());
while let Some(ext) = txn.get_external(&p)? {debug!("ext = {:?}", ext);p = ChangeId(L64(rand::thread_rng().gen()));
if v.flag.contains(EdgeFlags::PARENT)&& (v.flag.contains(EdgeFlags::BLOCK) || k.is_empty())&& !v.flag.contains(EdgeFlags::DELETED)
if v.flag().contains(EdgeFlags::PARENT)&& (v.flag().contains(EdgeFlags::BLOCK) || k.is_empty())&& !v.flag().contains(EdgeFlags::DELETED)
if e.flag.contains(EdgeFlags::PARENT) ^ down {debug_edge(txn, &channel, &mut f, v, e)?;let v = if e.flag.contains(EdgeFlags::PARENT) {txn.find_block_end(&channel, e.dest).unwrap()
if e.flag().contains(EdgeFlags::PARENT) ^ down {debug_edge(txn, &channel, &mut f, v, *e)?;let v = if e.flag().contains(EdgeFlags::PARENT) {txn.find_block_end(&channel, e.dest()).unwrap()
initialized_cursor!(tree, OwnedPathId, Inode, TreeTxnT, TreeError);initialized_cursor!(revtree, Inode, OwnedPathId, TreeTxnT, TreeError);
initialized_cursor!(tree, PathId, Inode, TreeTxnT, TreeError);initialized_cursor!(revtree, Inode, PathId, TreeTxnT, TreeError);
initialized_cursor!(remote, u64, (Hash, Merkle));initialized_rev_cursor!(remote, u64, (Hash, Merkle));
initialized_cursor!(remote, L64, Pair<SerializedHash, SerializedMerkle>);initialized_rev_cursor!(remote, L64, Pair<SerializedHash, SerializedMerkle>);
match is_ancestor_of(self.txn, self.txn.graph(&self.channel), self.key, touched) {Ok(true) => return self.txn.get_external(changeid).transpose(),
match is_ancestor_of(self.txn, self.txn.graph(&self.channel), self.key, *touched) {Ok(true) => return self.txn.get_external(&changeid).transpose().map(|x| x.map(|x| x.into())),
match is_ancestor_of(self.txn, self.txn.graph(&self.channel), self.key, touched) {Ok(true) => return self.txn.get_external(changeid).transpose(),
match is_ancestor_of(self.txn, self.txn.graph(&self.channel), self.key, *touched) {Ok(true) => return self.txn.get_external(&changeid).transpose().map(|x| x.map(From::from)),
k0,Some(Edge {flag,dest: Position {change: k1.change,pos: k1.start,},introduced_by,}),
&k0,Some(&SerializedEdge::new(flag, k1.change, k1.start, introduced_by)),
k0,Edge {flag,dest: Position {change: k1.change,pos: k1.start,},introduced_by,},
&k0,&SerializedEdge::new(flag, k1.change, k1.start, introduced_by)
) -> Result<Option<(u64, Merkle)>, TxnErr<T::GraphError>> {for x in T::cursor_revchangeset_ref(txn, txn.rev_changes(&c), Some(pos))? {let (n, (_, m)) = x?;
) -> Result<Option<(u64, SerializedMerkle)>, TxnErr<T::GraphError>> {for x in T::cursor_revchangeset_ref(txn, txn.rev_changes(&c), Some(pos.into()))? {let (&n, m) = x?;let n: u64 = n.into();
if let Some(aa) = txn.channel_has_state(txn.states(c0), state)? {return Ok((aa, b, state));
if let Some(aa) = txn.channel_has_state(txn.states(c0), &state)? {return Ok((aa.into(), b, state));
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]pub struct SerializedMerkle(pub [u8; 33]);impl PartialEq<Merkle> for SerializedMerkle {fn eq(&self, m: &Merkle) -> bool {match m {Merkle::Ed25519(q) => {(self.0)[0] == MerkleAlgorithm::Ed25519 as u8&& {let q = q.compress();q.as_bytes() == &(self.0)[1..]}}}}}impl PartialEq<SerializedMerkle> for Merkle {fn eq(&self, m: &SerializedMerkle) -> bool {m.eq(self)}}impl<'a> From<&'a Merkle> for SerializedMerkle {fn from(m: &'a Merkle) -> Self {let mut mm = [0; 33];match m {Merkle::Ed25519(q) => {mm[0] = MerkleAlgorithm::Ed25519 as u8;let q = q.compress();let q = q.as_bytes();(&mut mm[1..]).copy_from_slice(q);SerializedMerkle(mm)}}}}impl From<Merkle> for SerializedMerkle {fn from(m: Merkle) -> Self {let mut mm = [0; 33];match m {Merkle::Ed25519(q) => {mm[0] = MerkleAlgorithm::Ed25519 as u8;let q = q.compress();let q = q.as_bytes();(&mut mm[1..]).copy_from_slice(q);SerializedMerkle(mm)}}}}impl<'a> From<&'a SerializedMerkle> for Merkle {fn from(m: &'a SerializedMerkle) -> Self {assert_eq!((m.0)[0], MerkleAlgorithm::Ed25519 as u8);Merkle::Ed25519(curve25519_dalek::edwards::CompressedEdwardsY::from_slice(&(m.0)[1..]).decompress().unwrap(),)}}impl From<SerializedMerkle> for Merkle {fn from(m: SerializedMerkle) -> Self {assert_eq!((m.0)[0], MerkleAlgorithm::Ed25519 as u8);Merkle::Ed25519(curve25519_dalek::edwards::CompressedEdwardsY::from_slice(&(m.0)[1..]).decompress().unwrap(),)}}
}#[derive(Clone, Copy)]pub struct SerializedHash {pub(crate) t: u8,h: H}#[derive(Clone, Copy)]pub(crate) union H {none: (),blake3: [u8; 32],}pub(crate) const HASH_NONE: SerializedHash = SerializedHash {t: HashAlgorithm::None as u8,h: H { none: () },};use std::cmp::Ordering;impl PartialOrd for SerializedHash {fn partial_cmp(&self, b: &Self) -> Option<Ordering> {Some(self.t.cmp(&b.t))}}impl Ord for SerializedHash {fn cmp(&self, b: &Self) -> Ordering {match self.t.cmp(&b.t) {Ordering::Equal => {if self.t == HashAlgorithm::Blake3 as u8 {unsafe { self.h.blake3.cmp(&b.h.blake3) }} else {Ordering::Equal}}o => o}}}impl PartialEq for SerializedHash {fn eq(&self, b: &Self) -> bool {if self.t == HashAlgorithm::Blake3 as u8 && self.t == b.t {unsafe { self.h.blake3 == b.h.blake3 }} else if self.t == b.t {true} else {false}}}impl Eq for SerializedHash {}impl std::fmt::Debug for SerializedHash {fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {Hash::from(self).fmt(fmt)}}impl<'a> From<&'a SerializedHash> for Hash {fn from(s: &'a SerializedHash) -> Hash {if s.t == HashAlgorithm::Blake3 as u8 {Hash::Blake3(unsafe { s.h.blake3.clone() })} else if s.t == HashAlgorithm::None as u8 {Hash::None} else {panic!("Unknown hash algorithm {:?}", s.t)}}}impl From<SerializedHash> for Hash {fn from(s: SerializedHash) -> Hash {(&s).into()}
impl From<Hash> for SerializedHash {fn from(s: Hash) -> SerializedHash {(&s).into()}}impl<'a> From<&'a Hash> for SerializedHash {fn from(s: &'a Hash) -> Self {match s {Hash::Blake3(s) => SerializedHash {t: HashAlgorithm::Blake3 as u8,h: H { blake3: s.clone() },},Hash::None => SerializedHash {t: 0,h: H { none: () },}}}}
}/// The target half of an edge in the repository graph.#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]pub struct SerializedEdge([super::L64; 3]);impl std::fmt::Debug for SerializedEdge {fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {let pos = self.dest();use super::Base32;write!(fmt, "E({:?}, {}[{}], {})", self.flag(), pos.change.to_base32(), (pos.pos.0).0, self.introduced_by().to_base32())}}impl std::ops::SubAssign<EdgeFlags> for SerializedEdge {fn sub_assign(&mut self, e: EdgeFlags) {let ref mut f = (self.0)[0];f.0 = ((u64::from_le(f.0)) & !((e.bits() as u64) << 56)).to_le()}}impl SerializedEdge {pub fn flag(&self) -> EdgeFlags {let f = u64::from_le((self.0)[0].0);EdgeFlags::from_bits((f >> 56) as u8).unwrap()}pub fn dest(&self) -> Position<ChangeId> {let pos = u64::from_le((self.0[0]).0);Position {change: ChangeId((self.0)[1]),pos: ChangePosition(L64((pos & 0xffffffffffffff).to_le()))}}pub fn introduced_by(&self) -> ChangeId {ChangeId((self.0)[2])}}impl From<SerializedEdge> for Edge {fn from(s: SerializedEdge) -> Edge {Edge {flag: s.flag(),dest: s.dest(),introduced_by: s.introduced_by(),}}}impl From<Edge> for SerializedEdge {fn from(s: Edge) -> SerializedEdge {let pos = u64::from_le((s.dest.pos.0).0);assert!(pos < 1 << 56);SerializedEdge([(((s.flag.bits() as u64) << 56) | pos).into(),s.dest.change.0,s.introduced_by.0])}}impl<'a> From<&'a SerializedEdge> for Edge {fn from(s: &'a SerializedEdge) -> Edge {Edge {flag: s.flag(),dest: s.dest(),introduced_by: s.introduced_by(),}}}impl SerializedEdge {pub fn empty(dest: Position<ChangeId>, intro: ChangeId) -> Self {SerializedEdge([dest.pos.0, dest.change.0, intro.0])}pub fn new(flag: EdgeFlags, change: ChangeId, pos: ChangePosition, intro: ChangeId) -> Self {let pos = u64::from_le((pos.0).0);assert!(pos < 1 <<56);SerializedEdge([(pos | ((flag.bits() as u64) << 56)).into(), change.0, intro.0])}
debug!("no current name, inserting {:?} {:?}", file_id_, inode);if let Some(inode) = txn.get_tree(file_id_, None)? {crate::fs::rec_delete(txn, file_id.clone(), inode, true)
debug!("no current name, inserting {:?} {:?}", file_id, inode);if let Some(&inode) = txn.get_tree(&file_id, None)? {crate::fs::rec_delete(txn, &file_id, inode, true)
del_tree_with_rev(txn, fileid.as_file_id(), *inode)?;if let Some(vertex) = txn.get_inodes(*inode, None)? {
del_tree_with_rev(txn, &fileid, inode)?;for i in txn.iter_inodes().unwrap() {debug!("inodes = {:?}", i);}if let Some(&vertex) = txn.get_inodes(inode, None)? {
let source = txn.find_block_end(&channel, internal_pos(txn, &e.from, change_id)?)?;let target = txn.find_block(&channel, internal_pos(txn, &e.to.start_pos(), change_id)?)?;
let source = *txn.find_block_end(&channel, internal_pos(txn, &e.from, change_id)?)?;let target = *txn.find_block(&channel, internal_pos(txn, &e.to.start_pos(), change_id)?)?;
let p = txn.find_block(channel, edge.dest)?;assert!(!edge.flag.contains(EdgeFlags::FOLDER));
let p = *txn.find_block(channel, edge.dest())?;assert!(!edge.flag().contains(EdgeFlags::FOLDER));
if !is_alive(txn, channel, dest_vertex)? && !ws.repaired.contains(&dest_vertex) {if e.flag.contains(EdgeFlags::PARENT) {let p = txn.find_block_end(channel, e.dest)?;if !is_alive(txn, channel, p)? {
if !is_alive(txn, channel, &dest_vertex)? && !ws.repaired.contains(&dest_vertex) {if e.flag().contains(EdgeFlags::PARENT) {let p = *txn.find_block_end(channel, e.dest())?;if !is_alive(txn, channel, &p)? {
let p = txn.find_block_end(channel, edge.dest)?;ws.unknown_parents.push((dest_vertex, p, inode, edge.flag));
let p = *txn.find_block_end(channel, edge.dest())?;ws.unknown_parents.push((dest_vertex, p, inode, edge.flag()));
fn touched_files(&self, h: pristine::Hash) -> Result<Option<Touched<Self>>, Self::DepsError> {if let Some(id) = pristine::GraphTxnT::get_internal(self, h).map_err(|e| e.0)? {
fn touched_files(&self, h: &pristine::Hash) -> Result<Option<Touched<Self>>, Self::DepsError> {if let Some(id) = pristine::GraphTxnT::get_internal(self, &h.into()).map_err(|e| e.0)? {
del_tree_with_rev(txn, parent_id.as_file_id(), inode)?;if let Some(vertex) = txn.get_inodes(inode, None)? {del_inodes_with_rev(txn, inode, vertex)?;
del_tree_with_rev(txn, &parent_id, &inode)?;if let Some(&vertex) = txn.get_inodes(&inode, None)? {del_inodes_with_rev(txn, &inode, &vertex)?;
let mut stack = vec![Edge {dest: vertex0.start_pos(),introduced_by: ChangeId::ROOT,flag: EdgeFlags::empty(),}];
let mut stack = vec![SerializedEdge::empty(vertex0.start_pos(), ChangeId::ROOT)];
if v.flag.contains(EdgeFlags::PARENT) {if v.flag.contains(EdgeFlags::BLOCK)&& !v.flag.contains(EdgeFlags::DELETED)&& vertex != vertex0&& !v.flag.contains(EdgeFlags::PSEUDO)
if v.flag().contains(EdgeFlags::PARENT) {if v.flag().contains(EdgeFlags::BLOCK)&& !v.flag().contains(EdgeFlags::DELETED)&& *vertex != vertex0&& !v.flag().contains(EdgeFlags::PSEUDO)
for x in changeid_log(txn, &channel, 0)? {let (_, (ch, _)) = x?;let h = txn.get_external(ch)?.unwrap();deps.insert(h);
for x in changeid_log(txn, &channel, L64(0))? {let (_, p) = x?;let h = txn.get_external(&p.a)?.unwrap();deps.insert(h.into());
if let Some(parent) = txn.get_revtree(inode, None)?.map(|x| x.to_owned()) {del_tree_with_rev(txn, parent.as_file_id(), inode)?;
if let Some(parent) = txn.get_revtree(&inode, None)?.map(|x| x.to_owned()) {del_tree_with_rev(txn, &parent, &inode)?;
is_folder |= parent.flag.contains(EdgeFlags::PARENT | EdgeFlags::FOLDER);if parent.flag.contains(EdgeFlags::PARENT | EdgeFlags::BLOCK) {if parent.flag.contains(EdgeFlags::DELETED) {let introduced_by = txn.get_external(parent.introduced_by)?.unwrap();
is_folder |= parent.flag().contains(EdgeFlags::PARENT | EdgeFlags::FOLDER);if parent.flag().contains(EdgeFlags::PARENT | EdgeFlags::BLOCK) {if parent.flag().contains(EdgeFlags::DELETED) {let introduced_by = txn.get_external(&parent.introduced_by())?.unwrap().into();
if !e.flag.contains(EdgeFlags::FOLDER) {if e.flag.contains(EdgeFlags::PARENT) {let p = txn.find_block_end(channel, e.dest)?;
if !e.flag().contains(EdgeFlags::FOLDER) {if e.flag().contains(EdgeFlags::PARENT) {let p = txn.find_block_end(channel, e.dest())?;
let up = txn.find_block_end(channel, internal_pos(txn, &up, change_id)?)?;if !is_alive(txn, channel, up)? {
let up = *txn.find_block_end(channel, internal_pos(txn, &up, change_id)?)?;if !is_alive(txn, channel, &up)? {
debug!("al = {:?}, flag = {:?}", al, parent.flag);stack.push((anc, false, parent.flag.is_deleted(), al));
debug!("al = {:?}, flag = {:?}", al, parent.flag());stack.push((*anc, false, parent.flag().is_deleted(), al));
if e.flag.contains(EdgeFlags::PARENT) {if e.flag & (EdgeFlags::FOLDER | EdgeFlags::DELETED) == EdgeFlags::FOLDER {
if e.flag().contains(EdgeFlags::PARENT) {if e.flag() & (EdgeFlags::FOLDER | EdgeFlags::DELETED) == EdgeFlags::FOLDER {
checksum = "08944cea9021170d383287169859c0ca8147d9ec285978393109954448f33cc7"dependencies = ["once_cell",]
checksum = "fa189ef211c15ee602667a6fcfe1c1fd9e07d42250d2156382820fba33c9df80"
version = "0.4.13"
version = "0.4.14"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"dependencies = ["cfg-if 1.0.0",][[package]]name = "loom"version = "0.4.0"
version = "0.4.27"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15"dependencies = ["pin-project-internal 0.4.27",][[package]]name = "pin-project"version = "1.0.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "95b70b68509f17aa2857863b6fa00bf21fc93674c7a8893de2f469f6aa7ca2f2"dependencies = ["pin-project-internal 1.0.4",][[package]]name = "pin-project-internal"version = "0.4.27"
version = "1.0.5"
name = "tokio-stream"version = "0.1.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd"dependencies = ["futures-core","pin-project-lite","tokio",][[package]]