worktree: Don't open files >= 6GB in size (#27458)

Ben Kunkle created

Temporary Workaround For: #27283

This PR can (and should!) be reverted once the underlying inefficiencies
are resolved

Release Notes:

- Files that are 6GB or larger will now not open. This is a temporary
workaround for inefficient handling of large files resulting in
extremely high memory usage, often resulting in system freezing,
requiring a restart of Zed or the entire system.

Change summary

crates/project_panel/src/project_panel.rs |  3 +++
crates/worktree/src/worktree.rs           | 14 ++++++++++++++
2 files changed, 17 insertions(+)

Detailed changes

crates/project_panel/src/project_panel.rs 🔗

@@ -500,6 +500,9 @@ impl ProjectPanel {
                                             "{} is not shared by the host. This could be because it has been marked as `private`",
                                             file_path.display()
                                         )),
+                                        // See note in worktree.rs where this error originates. Returning Some in this case prevents
+                                        // the error popup from saying "Try Again", which is a red herring in this case
+                                        ErrorCode::Internal if e.to_string().contains("File is too large to load") => Some(e.to_string()),
                                         _ => None,
                                     }
                                 });

crates/worktree/src/worktree.rs 🔗

@@ -1808,6 +1808,20 @@ impl LocalWorktree {
 
         cx.spawn(async move |this, _cx| {
             let abs_path = abs_path?;
+            // WARN: Temporary workaround for #27283.
+            //       We are not efficient with our memory usage per file, and use in excess of 64GB for a 10GB file
+            //       Therefore, as a temporary workaround to prevent system freezes, we just bail before opening a file
+            //       if it is too large
+            //       5GB seems to be more reasonable, peaking at ~16GB, while 6GB jumps up to >24GB which seems like a
+            //       reasonable limit
+            {
+                const FILE_SIZE_MAX: u64 = 6 * 1024 * 1024 * 1024; // 6GB
+                if let Ok(Some(metadata)) = fs.metadata(&abs_path).await {
+                    if metadata.len >= FILE_SIZE_MAX {
+                        anyhow::bail!("File is too large to load");
+                    }
+                }
+            }
             let text = fs.load(&abs_path).await?;
 
             let worktree = this