d6cf61bfd4
The lockfile API is a handy way to obtain a file that is cleaned up if you die(). But sometimes you would need this sequence to work: 1. hold_lock_file_for_update() to get a file descriptor for writing; 2. write the contents out, without being able to decide if the results should be committed or rolled back; 3. do something else that makes the decision --- and this "something else" needs the lockfile not to have an open file descriptor for writing (e.g. Windows do not want a open file to be renamed); 4. call commit_lock_file() or rollback_lock_file() as appropriately. This adds close_lock_file() you can call between step 2 and 3 in the above sequence. Signed-off-by: Junio C Hamano <gitster@pobox.com>
75 lines
2.9 KiB
Plaintext
75 lines
2.9 KiB
Plaintext
lockfile API
|
|
============
|
|
|
|
The lockfile API serves two purposes:
|
|
|
|
* Mutual exclusion. When we write out a new index file, first
|
|
we create a new file `$GIT_DIR/index.lock`, write the new
|
|
contents into it, and rename it to the final destination
|
|
`$GIT_DIR/index`. We try to create the `$GIT_DIR/index.lock`
|
|
file with O_EXCL so that we can notice and fail when somebody
|
|
else is already trying to update the index file.
|
|
|
|
* Automatic cruft removal. After we create the "lock" file, we
|
|
may decide to `die()`, and we would want to make sure that we
|
|
remove the file that has not been committed to its final
|
|
destination. This is done by remembering the lockfiles we
|
|
created in a linked list and cleaning them up from an
|
|
`atexit(3)` handler. Outstanding lockfiles are also removed
|
|
when the program dies on a signal.
|
|
|
|
|
|
The functions
|
|
-------------
|
|
|
|
hold_lock_file_for_update::
|
|
|
|
Take a pointer to `struct lock_file`, the filename of
|
|
the final destination (e.g. `$GIT_DIR/index`) and a flag
|
|
`die_on_error`. Attempt to create a lockfile for the
|
|
destination and return the file descriptor for writing
|
|
to the file. If `die_on_error` flag is true, it dies if
|
|
a lock is already taken for the file; otherwise it
|
|
returns a negative integer to the caller on failure.
|
|
|
|
commit_lock_file::
|
|
|
|
Take a pointer to the `struct lock_file` initialized
|
|
with an earlier call to `hold_lock_file_for_update()`,
|
|
close the file descriptor and rename the lockfile to its
|
|
final destination. Returns 0 upon success, a negative
|
|
value on failure to close(2) or rename(2).
|
|
|
|
rollback_lock_file::
|
|
|
|
Take a pointer to the `struct lock_file` initialized
|
|
with an earlier call to `hold_lock_file_for_update()`,
|
|
close the file descriptor and remove the lockfile.
|
|
|
|
close_lock_file::
|
|
Take a pointer to the `struct lock_file` initialized
|
|
with an earlier call to `hold_lock_file_for_update()`,
|
|
and close the file descriptor. Returns 0 upon success,
|
|
a negative value on failure to close(2).
|
|
|
|
Because the structure is used in an `atexit(3)` handler, its
|
|
storage has to stay throughout the life of the program. It
|
|
cannot be an auto variable allocated on the stack.
|
|
|
|
Call `commit_lock_file()` or `rollback_lock_file()` when you are
|
|
done writing to the file descriptor. If you do not call either
|
|
and simply `exit(3)` from the program, an `atexit(3)` handler
|
|
will close and remove the lockfile.
|
|
|
|
If you need to close the file descriptor you obtained from
|
|
`hold_lock_file_for_update` function yourself, do so by calling
|
|
`close_lock_file()`. You should never call `close(2)` yourself!
|
|
Otherwise the `struct
|
|
lock_file` structure still remembers that the file descriptor
|
|
needs to be closed, and a later call to `commit_lock_file()` or
|
|
`rollback_lock_file()` will result in duplicate calls to
|
|
`close(2)`. Worse yet, if you `close(2)`, open another file
|
|
descriptor for completely different purpose, and then call
|
|
`commit_lock_file()` or `rollback_lock_file()`, they may close
|
|
that unrelated file descriptor.
|