On 09/13/2017 07:15 PM, Michael Haggerty wrote: > [...] > * `mmap()` the whole file rather than `read()`ing it. > [...] Apparently this doesn't work on Windows, because the `snapshot` is keeping the `packed-refs` file open too long, so the new file can't be renamed on top of it. I didn't realize that this is even allowed, but TIL that you can close a file while keeping it mmapped. Does that technique work on Windows? If so, I'll change v2 to do it as sketched below. Michael diff --git a/refs/packed-backend.c b/refs/packed-backend.c index 8235ac8506..95c1cd2a27 100644 --- a/refs/packed-backend.c +++ b/refs/packed-backend.c @@ -35,11 +35,8 @@ struct snapshot { */ struct packed_ref_store *refs; - /* - * The file descriptor of the `packed-refs` file (open in - * read-only mode), or -1 if it is not open. - */ - int fd; + /* Is the `packed-refs` file currently mmapped? */ + int mmapped; /* * The contents of the `packed-refs` file. If the file was @@ -135,12 +132,11 @@ static void acquire_snapshot(struct snapshot *snapshot) */ static void clear_snapshot_buffer(struct snapshot *snapshot) { - if (snapshot->fd >= 0) { + if (snapshot->mmapped) { if (munmap(snapshot->buf, snapshot->eof - snapshot->buf)) die_errno("error ummapping packed-refs file %s", snapshot->refs->path); - close(snapshot->fd); - snapshot->fd = -1; + snapshot->mmapped = 0; } else { free(snapshot->buf); } @@ -525,6 +521,7 @@ static const char *find_reference_location(struct snapshot *snapshot, static struct snapshot *create_snapshot(struct packed_ref_store *refs) { struct snapshot *snapshot = xcalloc(1, sizeof(*snapshot)); + int fd; struct stat st; size_t size; int sorted = 0; @@ -533,8 +530,8 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs) acquire_snapshot(snapshot); snapshot->peeled = PEELED_NONE; - snapshot->fd = open(refs->path, O_RDONLY); - if (snapshot->fd < 0) { + fd = open(refs->path, O_RDONLY); + if (fd < 0) { if (errno == ENOENT) { /* * This is OK; it just means that no @@ -549,15 +546,16 @@ static struct snapshot *create_snapshot(struct packed_ref_store *refs) } } - stat_validity_update(&snapshot->validity, snapshot->fd); + stat_validity_update(&snapshot->validity, fd); - if (fstat(snapshot->fd, &st) < 0) + if (fstat(fd, &st) < 0) die_errno("couldn't stat %s", refs->path); size = xsize_t(st.st_size); - snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, - snapshot->fd, 0); + snapshot->buf = xmmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); snapshot->eof = snapshot->buf + size; + snapshot->mmapped = 1; + close(fd); /* If the file has a header line, process it: */ if (snapshot->buf < snapshot->eof && *snapshot->buf == '#') {