Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,如何创建一个重用Git存储库的线程安全应用程序?_Java_Multithreading_Git_Thread Safety_Jgit - Fatal编程技术网

在Java中,如何创建一个重用Git存储库的线程安全应用程序?

在Java中,如何创建一个重用Git存储库的线程安全应用程序?,java,multithreading,git,thread-safety,jgit,Java,Multithreading,Git,Thread Safety,Jgit,我有一个开源web应用程序,其中磁盘上的同一存储库可以由多个线程使用。这涉及到对新分支执行git签出,并从存储库中访问文件 这方面存在一些问题: Git使用存储库中的锁文件,对操作使用悲观并发控制。正如所料,当同一存储库中同时调用了多个git checkout命令时,这会在JGit中引发异常 命令完成并删除Git的锁文件后,将访问存储库中的文件。这意味着另一次签出可能会在这个阶段更改文件,并导致对它们的错误解析 我曾考虑将同步方法和信号量作为解决方案,但不知道在这种情况下“最佳”的解决方案。

我有一个开源web应用程序,其中磁盘上的同一存储库可以由多个线程使用。这涉及到对新分支执行
git签出
,并从存储库中访问文件

这方面存在一些问题:

  • Git使用存储库中的锁文件,对操作使用悲观并发控制。正如所料,当同一存储库中同时调用了多个
    git checkout
    命令时,这会在JGit中引发异常

  • 命令完成并删除Git的锁文件后,将访问存储库中的文件。这意味着另一次签出可能会在这个阶段更改文件,并导致对它们的错误解析


我曾考虑将同步方法和信号量作为解决方案,但不知道在这种情况下“最佳”的解决方案。

以下是一些选项,它们不会破坏磁盘上的文件,因此对于多线程处理更安全:

  • 您可以直接查看文件内容,而无需签出整个提交:
    在命令行中,可以使用:

    git show <tree-ish>:path/to/file
    
    git show:path/to/file 或者以某种方式找到文件内容的哈希,然后调用:

    git cat-file -p <file-hash>
    
    git cat文件-p
    
    我不熟悉JGit,但您肯定可以找到一种使用其api执行这两个命令的方法

  • 如果您确实有理由签出完整提交,您可以签出到不同的工作树(请参见
    git-help-worktree
    ),
    或者构建一个归档(
    git-help-archive
    ),而不是真正签出提交

另外一点:所有这些命令都可以与裸git repo一起使用。

我建议使用git的纯Java实现。使用普通Java库使得不需要在服务器上提供合适版本的Git,并且还节省了一些处理周期,因为它不会为每个Git命令生成单独的进程

在大多数领域,JGit与GIT CLI实现一致。因此,除非您需要非常特定的Git特性,否则您将看不到任何区别

为了直接访问blob的内容,可以使用ObjectReader/ObjectLoader API。例如:

ObjectReader ObjectReader=repository.newObjectReader();
ObjectLoader=objectReader.open(blobId);
int type=objectLoader.getType();//常量.OBJ_BLOB
byte[]contents=objectLoader.getBytes();
有关直接访问Git对象数据库的更多信息,请参阅本文:

为了防止并发写访问,JGit使用与Git CLI相同的锁文件。如果写入访问因锁定失败而失败,JGit将返回相应的命令状态,允许应用程序代码稍后重试相同的操作

如果“乐观锁定”的方法不适合您的用例,您仍然可以求助于工作队列或其他同步方法。

试试。它有一个特殊的功能-锁定工作副本,这是一个线程和进程安全的文件夹

public static final String WORKSPACE_DIR = System.getProperty("java.io.tmpdir") + "scm4j-vcs-workspaces";
public static void main(String[] args) {
    IVCSWorkspace workspace = new VCSWorkspace(WORKSPACE_DIR);
    String repoUrl = "https://github.com/scm4j/scm4j-vcs-api";
    IVCSRepositoryWorkspace repoWorkspace = workspace.getVCSRepositoryWorkspace(repoUrl);
    try (IVCSLockedWorkingCopy wc = repoWorkspace.getVCSLockedWorkingCopy()) {
        // execute git-related operations within wc.getFolder()
    }
}

另请参见在独立工作副本中执行Git操作的示例库

听起来像是队列可以工作。实际上,考虑到这种情况,队列可能工作得很好,更新发生在同一存储库和不同的分支或路径中,在应用程序@Christopherschneidert中非常少见。感谢您提供在这种情况下更好地利用git的技巧。我看到的唯一问题是,当使用
git show
进行抓取时,“对于提交,它显示日志消息和文本差异”,而在这种情况下,我需要完整的内容,同样的主页上说:“对于普通blob,它显示普通内容。”(用git的说法,文件名为“blob”)。你需要从提交对象中得到什么?我的错误-误读了手册页-我做了一些测试,它的行为与预期的一样。实际上,我已经在使用JGit,但正在使用常规文件API而不是使用树/blob读取器访问本地文件,这造成了问题的第二个问题。大概这更类似于git show,只要我只需要读取访问,就不会锁定文件-我会做一些测试