git - 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);
解决方案
Git 使用几种方法来处理这种情况,而 libgit2 使用相同的方法来实现兼容性。
当 Git 需要更新具有固定名称的文件(例如索引或引用)时,它会创建一个具有相同名称但以 and 结尾的文件,.lock
然后O_CREAT
将O_EXCL
新内容写入该文件。然后它对现有文件使用原子重命名。在 Unix 系统上,这意味着打开旧文件的进程将看不到任何更改,而新进程将打开新文件。
如果你将一个对象写入对象存储,比如树或提交,那是无竞争的,因为它是唯一命名的。该文件存在或不存在,如果不存在,则将其创建为临时文件并重命名到位。重命名意味着如果一个相同的对象已经存在,它将被替换为一个相同的副本。
现在,您可能想要编写一个文件,例如索引,而其他人已经在这样做,在这种情况下,您将不得不等到锁定文件消失。通常等待的时间很短,所以等待不是问题。对于索引之类的东西,libgit2 提供了内存中的索引,它们都不需要锁定,并且如果您决定不需要它们,则更容易丢弃它们。
请注意,Git 不保证工作树中的原子操作,因为如果出现问题,确实不可能完全回滚。如果您只是处理存储库内容而不是更新工作树,那么 Git 应该没有竞争条件并且对多个用户具有合理的性能。
推荐阅读
- angular - 如何直接路由到我想要的组件,而不去主组件
- javascript - PhantomJS 在按钮单击事件后捕获下一页内容
- amazon-web-services - aws emr zeppelin 没有 jdbc 解释器
- android - 使用多部分改造的html文件上传
- spring - Spring Security 替换签名/验证器密钥
- azure-active-directory - 我们应该在更新后处理重用代码应用程序吗?
- c# - 如何使用 Roslyn 传递收集所有 MethodDeclarationSyntax?
- rest - 如何使用 Rest API 获取 Power BI 报表数据
- android - Github 上的新提交只有几个文件
- swift - 服务应该调用另一个服务还是应该获取自己的数据