首页 > 解决方案 > Git 或 libgit2 如何处理竞争条件?

问题描述

我使用libgit2并问自己,如果 2 个进程同时在同一个 repo 上执行写操作会发生什么?

下面的示例是提交回购的简单示例。它由许多命令组成。

如果一个进程A执行了前 3 个命令并挂了几秒钟,而另一个进程恰好执行了相同的命令顺序但运行了所有命令,那么A继续。我知道这很少见,因为 Git 操作主要是用户交互,用户很少同时使用 2 个这样的命令,我想了解 Git 中此类竞争条件的理论含义,以确保我不会破坏任何东西.

非常感谢!

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);

标签: gitlibgit2

解决方案


Git 使用几种方法来处理这种情况,而 libgit2 使用相同的方法来实现兼容性。

当 Git 需要更新具有固定名称的文件(例如索引或引用)时,它会创建一个具有相同名称但以 and 结尾的文件,.lock然后O_CREATO_EXCL新内容写入该文件。然后它对现有文件使用原子重命名。在 Unix 系统上,这意味着打开旧文件的进程将看不到任何更改,而新进程将打开新文件。

如果你将一个对象写入对象存储,比如树或提交,那是无竞争的,因为它是唯一命名的。该文件存在或不存在,如果不存在,则将其创建为临时文件并重命名到位。重命名意味着如果一个相同的对象已经存在,它将被替换为一个相同的副本。

现在,您可能想要编写一个文件,例如索引,而其他人已经在这样做,在这种情况下,您将不得不等到锁定文件消失。通常等待的时间很短,所以等待不是问题。对于索引之类的东西,libgit2 提供了内存中的索引,它们都不需要锁定,并且如果您决定不需要它们,则更容易丢弃它们。

请注意,Git 不保证工作树中的原子操作,因为如果出现问题,确实不可能完全回滚。如果您只是处理存储库内容而不是更新工作树,那么 Git 应该没有竞争条件并且对多个用户具有合理的性能。


推荐阅读