Reputation: 3219
I use libgit2
and asked myself, what happens if 2 processes execute a write operation on the same repo simultaneously?
The example below is a simple example to commit to a repo. It consists out of many commands.
What if a process A executes the first 3 commands and hangs for a few seconds, and another process happens to execute the same order of commands but runs through all, then A continues. I know this is rare since Git actions are mostly user interactions and a user rarely uses 2 of such commands at the same time, but I would like to understand the theoretical implications of such race coniditons in Git to be sure I don't break anything.
Thanks a lot!
check_lg2(git_repository_index(&index, repo), "Could not open repository index", NULL);
check_lg2(git_index_write_tree(&tree_oid, index), "Could not write tree", NULL);;
check_lg2(git_index_write(index), "Could not write index", NULL);
check_lg2(git_tree_lookup(&tree, repo, &tree_oid), "Error looking up tree", NULL);
check_lg2(git_signature_default(&signature, repo), "Error creating signature", NULL);
check_lg2(git_commit_create_v(
&commit_oid,
repo,
"HEAD",
signature,
signature,
NULL,
comment,
tree,
parent ? 1 : 0, parent), "Error creating commit", NULL);
Upvotes: 0
Views: 578
Reputation: 76539
Git uses several approaches to handle this case, and libgit2 uses the same approaches for compatibility.
When Git needs to update a file with a fixed name, like the index or a reference, it creates a file with the same name but ending in .lock
with O_CREAT
and O_EXCL
and then writes the new contents into that file. It then uses an atomic rename over the existing file. On Unix systems, that means that processes with the old file open will see no changes and new processes will open the new file.
If you write an object into the object store, like a tree or commit, that is race-free because it's uniquely named. Either the file exists or it doesn't, and if it doesn't, it's created as a temporary file and renamed into place. The rename means that if an identical object already existed, it would be replaced with an identical copy.
Now, it is possible that you want to write a file, like the index, and someone else is already doing so, in which case you'll have to wait until the lock file goes away. Usually the time to wait is rather short, so waiting isn't a problem. For things like the index, libgit2 offers in-memory indices which are both require no locking and are more easily discardable if you decide you don't need them.
Do note that Git doesn't guarantee atomic operations in the working tree because it's really not possible to roll back completely if things go wrong. If you're just dealing with the repository contents and not updating the working tree, then Git should be free of race conditions and reasonably performant for multiple users.
Upvotes: 1