git gc 似乎覆盖了一个包文件,留下了对 "old-xxx.pack" 的引用的打开文件描述符

git gc appearing to overwrite a packfile leaving open file descriptor holding reference to "old-xxx.pack"

在调试生产问题期间,我正在处理一个应用程序 (Gerrit),它在缓存结构中保存对 RandomAccessFiles 的引用。

这些文件引用了 git 个存储库包文件。

在带外 git gc(不在应用程序内)在没有更改的存储库上,似乎:

  1. 重写相同的包文件(相同的uuid);
  2. 文件描述符在 lsof 的输出列表中,格式为 (old-xxx.pack),但立即被标记(删除)。

我一直在为这个重命名搜索大量代码库,但无济于事。

我的问题是,如果 git gc 对具有打开的文件描述符的文件执行 rename/overwrite,这可能是文件系统的怪癖吗?

lsof 条目:

java    25700 user  246r      REG                8,3      5090   1855936 ~/gerrit/git/RepoF.git/objects/pack/old-f4b8054434be1a227bdf8b12729efc1719f39708.pack (deleted)

在 git gc:

期间通知事件
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ ACCESS pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ ACCESS pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ CREATE tmp_pack_rG4dBh
~/gerrit/git/RepoF.git/objects/pack/ OPEN tmp_pack_rG4dBh
~/gerrit/git/RepoF.git/objects/pack/ MODIFY tmp_pack_rG4dBh
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_WRITE,CLOSE tmp_pack_rG4dBh
~/gerrit/git/RepoF.git/objects/pack/ CREATE tmp_idx_NfF4Jh
~/gerrit/git/RepoF.git/objects/pack/ OPEN tmp_idx_NfF4Jh
~/gerrit/git/RepoF.git/objects/pack/ MODIFY tmp_idx_NfF4Jh
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_WRITE,CLOSE tmp_idx_NfF4Jh
~/gerrit/git/RepoF.git/objects/pack/ MOVED_FROM tmp_pack_rG4dBh
~/gerrit/git/RepoF.git/objects/pack/ MOVED_TO .tmp-27710-pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ MOVED_FROM tmp_idx_NfF4Jh
~/gerrit/git/RepoF.git/objects/pack/ MOVED_TO .tmp-27710-pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ MOVED_FROM pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
---> ~/gerrit/git/RepoF.git/objects/pack/ MOVED_TO old-f4b8054434be1a227bdf8b12729efc1719f39708.pack   <----
~/gerrit/git/RepoF.git/objects/pack/ MOVED_FROM pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ MOVED_TO old-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ ATTRIB .tmp-27710-pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ MOVED_FROM .tmp-27710-pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ MOVED_TO pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ ATTRIB .tmp-27710-pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ MOVED_FROM .tmp-27710-pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ MOVED_TO pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
---> ~/gerrit/git/RepoF.git/objects/pack/ DELETE old-f4b8054434be1a227bdf8b12729efc1719f39708.pack  <----
~/gerrit/git/RepoF.git/objects/pack/ DELETE old-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ ACCESS pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ ACCESS pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.pack
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE pack-f4b8054434be1a227bdf8b12729efc1719f39708.idx
~/gerrit/git/RepoF.git/objects/pack/ OPEN,ISDIR 
~/gerrit/git/RepoF.git/objects/pack/ CLOSE_NOWRITE,CLOSE,ISDIR 

如果您在没有更改的存储库中执行标准 git gc,这是预料之中的。 Git 通过内容的散列来命名其包文件。因为 Git 不会重新计算现有包的增量,所以当您 git gc 并且只有一个包并且没有松散的物体时,它很可能会将所有数据打包到一个与旧的。

发生这种情况时,Git 仍然有一个旧包打开的文件描述符,因为它不会立即关闭包。这是因为通常需要再次访问它们,所以它会尝试让它们打开一会儿。仍然打开的旧包更名为旧名称,新包更名到位;然后删除旧包。在 Unix 系统上,完全可以删除一个文件描述符打开的文件;当最后一个进程关闭其文件描述符时,存储将被释放。

因此,对于您所描述的情况,这一切似乎都是完全正常的。通常 git gc 不是空操作,因为额外的对象被添加到包中或从包中删除,或者多个包合并为一个。但是,如果您在 运行 之后立即执行 运行 一个 git gc 且没有中间更改,则这是预期的。