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,