From 2db69de81deea4682579d0b9e6da40b4e9558c05 Mon Sep 17 00:00:00 2001 From: Michael Haggerty Date: Mon, 10 Aug 2015 11:47:36 +0200 Subject: lockfile: move documentation to lockfile.h and lockfile.c Rearrange/rewrite it somewhat to fit its new environment. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- Documentation/technical/api-lockfile.txt | 220 ------------------------------- 1 file changed, 220 deletions(-) delete mode 100644 Documentation/technical/api-lockfile.txt (limited to 'Documentation/technical/api-lockfile.txt') diff --git a/Documentation/technical/api-lockfile.txt b/Documentation/technical/api-lockfile.txt deleted file mode 100644 index 93b5f23e4c..0000000000 --- a/Documentation/technical/api-lockfile.txt +++ /dev/null @@ -1,220 +0,0 @@ -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 `.lock`, write the new file - contents into it, and then rename the lockfile to its final - destination ``. We create the `.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 either: - - * writing to the file descriptor returned by the `hold_lock_file_*` - functions (also available via `lock->fd`). - - * calling `fdopen_lock_file` to get a `FILE` pointer for the open - file and writing to the file using stdio. - -When finished writing, the caller can: - -* Close the file descriptor and rename the lockfile to its final - destination by calling `commit_lock_file` or `commit_lock_file_to`. - -* 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`, - `commit_lock_file_to`, `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`, -`commit_lock_file_to`, `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)` or `fclose(3)` -yourself! Otherwise the `struct lock_file` structure would still think -that the file descriptor needs to be closed, and a commit or rollback -would result in duplicate calls to `close(2)`. Worse yet, if you close -and then later open another file descriptor for a completely different -purpose, then a commit or rollback 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()`. - -Similarly, `commit_lock_file`, `commit_lock_file_to`, and -`close_lock_file` return 0 on success. On failure they set `errno` -appropriately, do their best to roll back the lockfile, and return -1. - - -Flags ------ - -The following flags can be passed to `hold_lock_file_for_update` or -`hold_lock_file_for_append`: - -LOCK_NO_DEREF:: - - Usually symbolic links in the destination path are resolved - and the lockfile is created by adding ".lock" to the resolved - path. If `LOCK_NO_DEREF` 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. - -fdopen_lock_file:: - - Associate a stdio stream with the lockfile. Return NULL - (*without* rolling back the lockfile) on error. The stream is - closed automatically when `close_lock_file` is called or when - the file is committed or rolled back. - -get_locked_file_path:: - - Return the path of the file that is locked by the specified - lock_file object. The caller must free the memory. - -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. On failure, roll back the lock file and return -1, - with `errno` set to the value from the failing call 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. - -commit_lock_file_to:: - - Like `commit_lock_file()`, except that it takes an explicit - `path` argument to which the lockfile should be renamed. The - `path` must be on the same filesystem as the lock file. - -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. It is a NOOP to call - `rollback_lock_file()` for a `lock_file` object that has - already been committed or rolled back. - -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`. Close the file descriptor (and - the file pointer if it has been opened using - `fdopen_lock_file`). Return 0 upon success. On failure to - `close(2)`, return a negative value and roll back the lock - file. Usually `commit_lock_file`, `commit_lock_file_to`, 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. -- cgit v1.2.3