| lockfile API |
| ============ |
| |
| The lockfile API serves two purposes: |
| |
| * Mutual exclusion and atomic file updates. When we want to change a |
| file, we create a lockfile `<filename>.lock`, write the new file |
| contents into it, and then rename the lockfile to its final |
| destination `<filename>`. We create the `<filename>.lock` file with |
| `O_CREAT|O_EXCL` so that we can notice and fail if somebody else has |
| already locked the file, then atomically rename the lockfile to its |
| final destination to commit the changes and unlock the file. |
| |
| * Automatic cruft removal. If the program exits after we lock a file |
| but before the changes have been committed, we want to make sure |
| that we remove the lockfile. This is done by remembering the |
| lockfiles we have created in a linked list and setting up an |
| `atexit(3)` handler and a signal handler that clean up the |
| lockfiles. This mechanism ensures that outstanding lockfiles are |
| cleaned up if the program exits (including when `die()` is called) |
| or if the program dies on a signal. |
| |
| Please note that lockfiles only block other writers. Readers do not |
| block, but they are guaranteed to see either the old contents of the |
| file or the new contents of the file (assuming that the filesystem |
| implements `rename(2)` atomically). |
| |
| |
| Calling sequence |
| ---------------- |
| |
| The caller: |
| |
| * Allocates a `struct lock_file` either as a static variable or on the |
| heap, initialized to zeros. Once you use the structure to call the |
| `hold_lock_file_*` family of functions, it belongs to the lockfile |
| subsystem and its storage must remain valid throughout the life of |
| the program (i.e. you cannot use an on-stack variable to hold this |
| structure). |
| |
| * Attempts to create a lockfile by passing that variable and the path |
| of the final destination (e.g. `$GIT_DIR/index`) to |
| `hold_lock_file_for_update` or `hold_lock_file_for_append`. |
| |
| * Writes new content for the destination file by writing to the file |
| descriptor returned by those functions (also available via |
| `lock->fd`). |
| |
| When finished writing, the caller can: |
| |
| * Close the file descriptor and rename the lockfile to its final |
| destination by calling `commit_lock_file`. |
| |
| * Close the file descriptor and remove the lockfile by calling |
| `rollback_lock_file`. |
| |
| * Close the file descriptor without removing or renaming the lockfile |
| by calling `close_lock_file`, and later call `commit_lock_file`, |
| `rollback_lock_file`, or `reopen_lock_file`. |
| |
| Even after the lockfile is committed or rolled back, the `lock_file` |
| object must not be freed or altered by the caller. However, it may be |
| reused; just pass it to another call of `hold_lock_file_for_update` or |
| `hold_lock_file_for_append`. |
| |
| If the program exits before you have called one of `commit_lock_file`, |
| `rollback_lock_file`, or `close_lock_file`, an `atexit(3)` handler |
| will close and remove the lockfile, rolling back any uncommitted |
| changes. |
| |
| If you need to close the file descriptor you obtained from a |
| `hold_lock_file_*` function yourself, do so by calling |
| `close_lock_file`. You should never call `close(2)` yourself! |
| Otherwise the `struct lock_file` structure would still think that the |
| file descriptor needs to be closed, and a later call to |
| `commit_lock_file` or `rollback_lock_file` or program exit would |
| result in duplicate calls to `close(2)`. Worse yet, if you `close(2)` |
| and then later open another file descriptor for a completely different |
| purpose, then a call to `commit_lock_file` or `rollback_lock_file` |
| might close that unrelated file descriptor. |
| |
| |
| Error handling |
| -------------- |
| |
| The `hold_lock_file_*` functions return a file descriptor on success |
| or -1 on failure (unless `LOCK_DIE_ON_ERROR` is used; see below). On |
| errors, `errno` describes the reason for failure. Errors can be |
| reported by passing `errno` to one of the following helper functions: |
| |
| unable_to_lock_message:: |
| |
| Append an appropriate error message to a `strbuf`. |
| |
| unable_to_lock_error:: |
| |
| Emit an appropriate error message using `error()`. |
| |
| unable_to_lock_die:: |
| |
| Emit an appropriate error message and `die()`. |
| |
| |
| Flags |
| ----- |
| |
| The following flags can be passed to `hold_lock_file_for_update` or |
| `hold_lock_file_for_append`: |
| |
| LOCK_NODEREF:: |
| |
| Usually symbolic links in the destination path are resolved |
| and the lockfile is created by adding ".lock" to the resolved |
| path. If `LOCK_NODEREF` is set, then the lockfile is created |
| by adding ".lock" to the path argument itself. This option is |
| used, for example, when locking a symbolic reference, which |
| for backwards-compatibility reasons can be a symbolic link |
| containing the name of the referred-to-reference. |
| |
| LOCK_DIE_ON_ERROR:: |
| |
| If a lock is already taken for the file, `die()` with an error |
| message. If this option is not specified, trying to lock a |
| file that is already locked returns -1 to the caller. |
| |
| |
| The functions |
| ------------- |
| |
| hold_lock_file_for_update:: |
| |
| Take a pointer to `struct lock_file`, the path of the file to |
| be locked (e.g. `$GIT_DIR/index`) and a flags argument (see |
| above). Attempt to create a lockfile for the destination and |
| return the file descriptor for writing to the file. |
| |
| hold_lock_file_for_append:: |
| |
| Like `hold_lock_file_for_update`, but before returning copy |
| the existing contents of the file (if any) to the lockfile and |
| position its write pointer at the end of the file. |
| |
| commit_lock_file:: |
| |
| Take a pointer to the `struct lock_file` initialized with an |
| earlier call to `hold_lock_file_for_update` or |
| `hold_lock_file_for_append`, close the file descriptor and |
| rename the lockfile to its final destination. Return 0 upon |
| success or a negative value on failure to `close(2)` or |
| `rename(2)`. It is a bug to call `commit_lock_file()` for a |
| `lock_file` object that is not currently locked. |
| |
| rollback_lock_file:: |
| |
| Take a pointer to the `struct lock_file` initialized with an |
| earlier call to `hold_lock_file_for_update` or |
| `hold_lock_file_for_append`, 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` or |
| `hold_lock_file_for_append`, and close the file descriptor. |
| Return 0 upon success. On failure to `close(2)`, return a |
| negative value and rollback the lock file. Usually |
| `commit_lock_file` or `rollback_lock_file` should eventually |
| be called if `close_lock_file` succeeds. |
| |
| reopen_lock_file:: |
| |
| Re-open a lockfile that has been closed (using |
| `close_lock_file`) but not yet committed or rolled back. This |
| can be used to implement a sequence of operations like the |
| following: |
| |
| * Lock file. |
| |
| * Write new contents to lockfile, then `close_lock_file` to |
| cause the contents to be written to disk. |
| |
| * Pass the name of the lockfile to another program to allow it |
| (and nobody else) to inspect the contents you wrote, while |
| still holding the lock yourself. |
| |
| * `reopen_lock_file` to reopen the lockfile. Make further |
| updates to the contents. |
| |
| * `commit_lock_file` to make the final version permanent. |