Show More
@@ -464,29 +464,38 b' impl Repo {' | |||||
464 | let data_filename = format!("dirstate.{}", uuid); |
|
464 | let data_filename = format!("dirstate.{}", uuid); | |
465 | let data_filename = self.hg_vfs().join(data_filename); |
|
465 | let data_filename = self.hg_vfs().join(data_filename); | |
466 | let mut options = std::fs::OpenOptions::new(); |
|
466 | let mut options = std::fs::OpenOptions::new(); | |
467 | if append { |
|
467 | options.write(true); | |
468 | options.append(true); |
|
468 | ||
469 | } else { |
|
469 | // Why are we not using the O_APPEND flag when appending? | |
470 | options.write(true).create_new(true); |
|
470 | // | |
|
471 | // - O_APPEND makes it trickier to deal with garbage at the end of | |||
|
472 | // the file, left by a previous uncommitted transaction. By | |||
|
473 | // starting the write at [old_data_size] we make sure we erase | |||
|
474 | // all such garbage. | |||
|
475 | // | |||
|
476 | // - O_APPEND requires to special-case 0-byte writes, whereas we | |||
|
477 | // don't need that. | |||
|
478 | // | |||
|
479 | // - Some OSes have bugs in implementation O_APPEND: | |||
|
480 | // revlog.py talks about a Solaris bug, but we also saw some ZFS | |||
|
481 | // bug: https://github.com/openzfs/zfs/pull/3124, | |||
|
482 | // https://github.com/openzfs/zfs/issues/13370 | |||
|
483 | // | |||
|
484 | if !append { | |||
|
485 | options.create_new(true); | |||
471 | } |
|
486 | } | |
|
487 | ||||
472 | let data_size = (|| { |
|
488 | let data_size = (|| { | |
473 | // TODO: loop and try another random ID if !append and this |
|
489 | // TODO: loop and try another random ID if !append and this | |
474 | // returns `ErrorKind::AlreadyExists`? Collision chance of two |
|
490 | // returns `ErrorKind::AlreadyExists`? Collision chance of two | |
475 | // random IDs is one in 2**32 |
|
491 | // random IDs is one in 2**32 | |
476 | let mut file = options.open(&data_filename)?; |
|
492 | let mut file = options.open(&data_filename)?; | |
477 |
if |
|
493 | if append { | |
478 | // If we're not appending anything, the data size is the |
|
494 | file.seek(SeekFrom::Start(old_data_size as u64))?; | |
479 | // same as in the previous docket. It is *not* the file |
|
495 | } | |
480 | // length, since it could have garbage at the end. |
|
|||
481 | // We don't have to worry about it when we do have data |
|
|||
482 | // to append since we rewrite the root node in this case. |
|
|||
483 | Ok(old_data_size as u64) |
|
|||
484 | } else { |
|
|||
485 |
|
|
496 | file.write_all(&data)?; | |
486 |
|
|
497 | file.flush()?; | |
487 | // TODO: use https://doc.rust-lang.org/std/io/trait.Seek.html#method.stream_position when we require Rust 1.51+ |
|
|||
488 |
|
|
498 | file.seek(SeekFrom::Current(0)) | |
489 | } |
|
|||
490 | })() |
|
499 | })() | |
491 | .when_writing_file(&data_filename)?; |
|
500 | .when_writing_file(&data_filename)?; | |
492 |
|
501 |
General Comments 0
You need to be logged in to leave comments.
Login now