Mercurial > public > mercurial-scm > hg
comparison rust/hg-core/src/repo.rs @ 49217:13dfad0f9f7a
branching: merge stable into default
author | Rapha?l Gom?s <rgomes@octobus.net> |
---|---|
date | Wed, 25 May 2022 13:28:24 +0200 |
parents | 90a15199cbc6 2d0e22171ef9 |
children | be019ac8c1e4 e98fd81bb151 |
comparison
equal
deleted
inserted
replaced
49212:d3d3495a5749 | 49217:13dfad0f9f7a |
---|---|
454 }; | 454 }; |
455 | 455 |
456 let data_filename = format!("dirstate.{}", uuid); | 456 let data_filename = format!("dirstate.{}", uuid); |
457 let data_filename = self.hg_vfs().join(data_filename); | 457 let data_filename = self.hg_vfs().join(data_filename); |
458 let mut options = std::fs::OpenOptions::new(); | 458 let mut options = std::fs::OpenOptions::new(); |
459 if append { | 459 options.write(true); |
460 options.append(true); | 460 |
461 } else { | 461 // Why are we not using the O_APPEND flag when appending? |
462 options.write(true).create_new(true); | 462 // |
463 } | 463 // - O_APPEND makes it trickier to deal with garbage at the end of |
464 // the file, left by a previous uncommitted transaction. By | |
465 // starting the write at [old_data_size] we make sure we erase | |
466 // all such garbage. | |
467 // | |
468 // - O_APPEND requires to special-case 0-byte writes, whereas we | |
469 // don't need that. | |
470 // | |
471 // - Some OSes have bugs in implementation O_APPEND: | |
472 // revlog.py talks about a Solaris bug, but we also saw some ZFS | |
473 // bug: https://github.com/openzfs/zfs/pull/3124, | |
474 // https://github.com/openzfs/zfs/issues/13370 | |
475 // | |
476 if !append { | |
477 options.create_new(true); | |
478 } | |
479 | |
464 let data_size = (|| { | 480 let data_size = (|| { |
465 // TODO: loop and try another random ID if !append and this | 481 // TODO: loop and try another random ID if !append and this |
466 // returns `ErrorKind::AlreadyExists`? Collision chance of two | 482 // returns `ErrorKind::AlreadyExists`? Collision chance of two |
467 // random IDs is one in 2**32 | 483 // random IDs is one in 2**32 |
468 let mut file = options.open(&data_filename)?; | 484 let mut file = options.open(&data_filename)?; |
469 if data.is_empty() { | 485 if append { |
470 // If we're not appending anything, the data size is the | 486 file.seek(SeekFrom::Start(old_data_size as u64))?; |
471 // same as in the previous docket. It is *not* the file | |
472 // length, since it could have garbage at the end. | |
473 // We don't have to worry about it when we do have data | |
474 // to append since we rewrite the root node in this case. | |
475 Ok(old_data_size as u64) | |
476 } else { | |
477 file.write_all(&data)?; | |
478 file.flush()?; | |
479 // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+ | |
480 file.seek(SeekFrom::Current(0)) | |
481 } | 487 } |
488 file.write_all(&data)?; | |
489 file.flush()?; | |
490 file.seek(SeekFrom::Current(0)) | |
482 })() | 491 })() |
483 .when_writing_file(&data_filename)?; | 492 .when_writing_file(&data_filename)?; |
484 | 493 |
485 let packed_dirstate = DirstateDocket::serialize( | 494 let packed_dirstate = DirstateDocket::serialize( |
486 parents, | 495 parents, |