diff --git a/src/install/PackageManager.zig b/src/install/PackageManager.zig index 05b4d669f2..9bbfe8772f 100644 --- a/src/install/PackageManager.zig +++ b/src/install/PackageManager.zig @@ -19,7 +19,7 @@ scripts_node: ?*Progress.Node = null, progress_name_buf: [768]u8 = undefined, progress_name_buf_dynamic: []u8 = &[_]u8{}, cpu_count: u32 = 0, -is_cache_directory_an_overlay_fs: ?bool = null, +is_cache_directory_remote: ?bun.sys.RemoteFileSystem = null, track_installed_bin: TrackInstalledBin = .{ .none = {}, }, @@ -381,22 +381,22 @@ pub fn computeIsContinuousIntegration(this: *PackageManager) bool { return this.env.isCI(); } -pub fn isCacheDirectoryRemote(this: *PackageManager) bool { +pub fn isCacheDirectoryRemote(this: *PackageManager) bun.sys.RemoteFileSystem { if (comptime Environment.isWindows) { // TODO: - return false; + return .none; } - if (this.is_cache_directory_an_overlay_fs) |is_overlay_fs| { - return is_overlay_fs; + if (this.is_cache_directory_remote) |remote_fs| { + return remote_fs; } const statfs = bun.sys.statfs(this.cache_directory_path).unwrap() catch { - this.is_cache_directory_an_overlay_fs = false; - return false; + this.is_cache_directory_remote = .none; + return .none; }; - this.is_cache_directory_an_overlay_fs = bun.sys.isRemoteFilesystem(&statfs); - return this.is_cache_directory_an_overlay_fs.?; + this.is_cache_directory_remote = bun.sys.RemoteFileSystem.get(&statfs); + return this.is_cache_directory_remote.?; } pub inline fn isContinuousIntegration(this: *PackageManager) bool { @@ -576,6 +576,34 @@ fn httpThreadOnInitError(err: HTTP.InitError, opts: HTTP.HTTPThread.InitOpts) no Global.crash(); } +pub fn useCopyfileBackendIfFaster(this: *PackageManager) void { + if (this.options.do.auto_choose_backend) { + // Only do this once. + this.options.do.auto_choose_backend = false; + + const PackageInstall = @import("./PackageInstall.zig").PackageInstall; + if (PackageInstall.supported_method == .hardlink) { + // Vercel builds: + // + // --backend=copyfile: + // 268 packages installed [5.06s] + // + // --backend=hardlink + // 268 packages installed [11.55s] + if (this.isCacheDirectoryRemote() == .overlayfs) { + if (PackageManager.verbose_install) { + if (this.options.node_linker == .hoisted) { + Output.prettyErrorln("[PackageManager] using \"copyfile\" backend instead of \"hardlink\" for faster installs in OverlayFS. Consider --linker=isolated to further speed up installs.", .{}); + } else { + Output.prettyErrorln("[PackageManager] using \"copyfile\" backend instead of \"hardlink\" for faster installs in OverlayFS", .{}); + } + } + PackageInstall.supported_method = .copyfile; + } + } + } +} + pub fn init( ctx: Command.Context, cli: CommandLineArguments, diff --git a/src/install/PackageManager/PackageManagerOptions.zig b/src/install/PackageManager/PackageManagerOptions.zig index 8e2dfbe606..765fce438d 100644 --- a/src/install/PackageManager/PackageManagerOptions.zig +++ b/src/install/PackageManager/PackageManagerOptions.zig @@ -565,6 +565,7 @@ pub fn load( if (cli.backend) |backend| { PackageInstall.supported_method = backend; + this.do.auto_choose_backend = false; } this.do.update_to_latest = cli.latest; @@ -666,7 +667,8 @@ pub const Do = packed struct(u16) { trust_dependencies_from_args: bool = false, update_to_latest: bool = false, analyze: bool = false, - _: u4 = 0, + auto_choose_backend: bool = true, + _: u3 = 0, }; pub const Enable = packed struct(u16) { diff --git a/src/install/PackageManager/runTasks.zig b/src/install/PackageManager/runTasks.zig index 580f75652a..18cbd3eee4 100644 --- a/src/install/PackageManager/runTasks.zig +++ b/src/install/PackageManager/runTasks.zig @@ -270,7 +270,7 @@ pub fn runTasks( if (manager.options.enable.manifest_cache) { if (!bun.getRuntimeFeatureFlag(.BUN_FEATURE_FLAG_MANIFEST_CACHE_NO_SAVE_TTL)) { - if (!manager.isCacheDirectoryRemote()) { + if (manager.isCacheDirectoryRemote() == .none) { Npm.PackageManifest.Serializer.saveAsync( &entry.value_ptr.manifest, manager.scopeForPackageName(name.slice()), diff --git a/src/install/hoisted_install.zig b/src/install/hoisted_install.zig index e919695d1c..4d3f92a96a 100644 --- a/src/install/hoisted_install.zig +++ b/src/install/hoisted_install.zig @@ -83,6 +83,7 @@ pub fn installHoistedPackages( var summary = PackageInstall.Summary{}; { + this.useCopyfileBackendIfFaster(); var iterator = Lockfile.Tree.Iterator(.node_modules).init(this.lockfile); if (comptime Environment.isPosix) { Bin.Linker.ensureUmask(); diff --git a/src/install/isolated_install.zig b/src/install/isolated_install.zig index 5c0fb304a8..524e44446f 100644 --- a/src/install/isolated_install.zig +++ b/src/install/isolated_install.zig @@ -620,6 +620,8 @@ pub fn installIsolatedPackages( var seen_workspace_ids: std.AutoHashMapUnmanaged(PackageID, void) = .empty; defer seen_workspace_ids.deinit(lockfile.allocator); + manager.useCopyfileBackendIfFaster(); + var installer: Store.Installer = .{ .lockfile = lockfile, .manager = manager, diff --git a/src/sys.zig b/src/sys.zig index f2a81f7c9b..e4e4b85cd7 100644 --- a/src/sys.zig +++ b/src/sys.zig @@ -827,96 +827,10 @@ pub fn stat(path: [:0]const u8) Maybe(bun.Stat) { } } -pub fn isRemoteFilesystem(stat_fs: *const bun.StatFS) bool { - - // The following filesystem types may appear in f_type: - - // ADFS_SUPER_MAGIC 0xadf5 - // AFFS_SUPER_MAGIC 0xadff - // AFS_SUPER_MAGIC 0x5346414f - // ANON_INODE_FS_MAGIC 0x09041934 /* Anonymous inode FS (for - // pseudofiles that have no name; - // e.g., epoll, signalfd, bpf) */ - // AUTOFS_SUPER_MAGIC 0x0187 - // BDEVFS_MAGIC 0x62646576 - // BEFS_SUPER_MAGIC 0x42465331 - // BFS_MAGIC 0x1badface - // BINFMTFS_MAGIC 0x42494e4d - // BPF_FS_MAGIC 0xcafe4a11 - // BTRFS_SUPER_MAGIC 0x9123683e - // BTRFS_TEST_MAGIC 0x73727279 - // CGROUP_SUPER_MAGIC 0x27e0eb /* Cgroup pseudo FS */ - // CGROUP2_SUPER_MAGIC 0x63677270 /* Cgroup v2 pseudo FS */ - // CIFS_MAGIC_NUMBER 0xff534d42 - // CODA_SUPER_MAGIC 0x73757245 - // COH_SUPER_MAGIC 0x012ff7b7 - // CRAMFS_MAGIC 0x28cd3d45 - // DEBUGFS_MAGIC 0x64626720 - // DEVFS_SUPER_MAGIC 0x1373 /* Linux 2.6.17 and earlier */ - // DEVPTS_SUPER_MAGIC 0x1cd1 - // ECRYPTFS_SUPER_MAGIC 0xf15f - // EFIVARFS_MAGIC 0xde5e81e4 - // EFS_SUPER_MAGIC 0x00414a53 - // EXT_SUPER_MAGIC 0x137d /* Linux 2.0 and earlier */ - // EXT2_OLD_SUPER_MAGIC 0xef51 - // EXT2_SUPER_MAGIC 0xef53 - // EXT3_SUPER_MAGIC 0xef53 - // EXT4_SUPER_MAGIC 0xef53 - // F2FS_SUPER_MAGIC 0xf2f52010 - // FUSE_SUPER_MAGIC 0x65735546 - // FUTEXFS_SUPER_MAGIC 0xbad1dea /* Unused */ - // HFS_SUPER_MAGIC 0x4244 - // HOSTFS_SUPER_MAGIC 0x00c0ffee - // HPFS_SUPER_MAGIC 0xf995e849 - // HUGETLBFS_MAGIC 0x958458f6 - // ISOFS_SUPER_MAGIC 0x9660 - // JFFS2_SUPER_MAGIC 0x72b6 - // JFS_SUPER_MAGIC 0x3153464a - // MINIX_SUPER_MAGIC 0x137f /* original minix FS */ - // MINIX_SUPER_MAGIC2 0x138f /* 30 char minix FS */ - // MINIX2_SUPER_MAGIC 0x2468 /* minix V2 FS */ - // MINIX2_SUPER_MAGIC2 0x2478 /* minix V2 FS, 30 char names */ - // MINIX3_SUPER_MAGIC 0x4d5a /* minix V3 FS, 60 char names */ - // MQUEUE_MAGIC 0x19800202 /* POSIX message queue FS */ - // MSDOS_SUPER_MAGIC 0x4d44 - // MTD_INODE_FS_MAGIC 0x11307854 - // NCP_SUPER_MAGIC 0x564c - // NFS_SUPER_MAGIC 0x6969 - // NILFS_SUPER_MAGIC 0x3434 - // NSFS_MAGIC 0x6e736673 - // NTFS_SB_MAGIC 0x5346544e - // OCFS2_SUPER_MAGIC 0x7461636f - // OPENPROM_SUPER_MAGIC 0x9fa1 - // OVERLAYFS_SUPER_MAGIC 0x794c7630 - // PIPEFS_MAGIC 0x50495045 - // PROC_SUPER_MAGIC 0x9fa0 /* /proc FS */ - // PSTOREFS_MAGIC 0x6165676c - // QNX4_SUPER_MAGIC 0x002f - // QNX6_SUPER_MAGIC 0x68191122 - // RAMFS_MAGIC 0x858458f6 - // REISERFS_SUPER_MAGIC 0x52654973 - // ROMFS_MAGIC 0x7275 - // SECURITYFS_MAGIC 0x73636673 - // SELINUX_MAGIC 0xf97cff8c - // SMACK_MAGIC 0x43415d53 - // SMB_SUPER_MAGIC 0x517b - // SMB2_MAGIC_NUMBER 0xfe534d42 - // SOCKFS_MAGIC 0x534f434b - // SQUASHFS_MAGIC 0x73717368 - // SYSFS_MAGIC 0x62656572 - // SYSV2_SUPER_MAGIC 0x012ff7b6 - // SYSV4_SUPER_MAGIC 0x012ff7b5 - // TMPFS_MAGIC 0x01021994 - // TRACEFS_MAGIC 0x74726163 - // UDF_SUPER_MAGIC 0x15013346 - // UFS_MAGIC 0x00011954 - // USBDEVICE_SUPER_MAGIC 0x9fa2 - // V9FS_MAGIC 0x01021997 - // VXFS_SUPER_MAGIC 0xa501fcf5 - // XENFS_SUPER_MAGIC 0xabba1974 - // XENIX_SUPER_MAGIC 0x012ff7b4 - // XFS_SUPER_MAGIC 0x58465342 - // _XIAFS_SUPER_MAGIC 0x012fd16d +pub const RemoteFileSystem = enum { + overlayfs, + remote, + none, const remote_fs_magic = [_]u32{ 0xadf5, // ADFS_SUPER_MAGIC @@ -930,7 +844,6 @@ pub fn isRemoteFilesystem(stat_fs: *const bun.StatFS) bool { 0x517b, // SMB_SUPER_MAGIC 0xfe534d42, // SMB2_MAGIC_NUMBER 0x65735546, // FUSE_SUPER_MAGIC - 0x794c7630, // OVERLAYFS_SUPER_MAGIC 0x6165676c, // PSTOREFS_MAGIC 0x68191122, // QNX6_SUPER_MAGIC 0x62646576, // BDEVFS_MAGIC @@ -940,14 +853,22 @@ pub fn isRemoteFilesystem(stat_fs: *const bun.StatFS) bool { 0x64626720, // DEBUGFS_MAGIC }; - for (remote_fs_magic) |magic| { - if (stat_fs.f_type & magic != 0) { - return true; - } - } + const OVERLAYFS_MAGIC = 0x794c7630; - return false; -} + pub fn get(stat_fs: *const bun.StatFS) RemoteFileSystem { + if (stat_fs.f_type == OVERLAYFS_MAGIC) { + return .overlayfs; + } + + for (remote_fs_magic) |magic| { + if (stat_fs.f_type == magic) { + return .remote; + } + } + + return .none; + } +}; pub fn statfs(path: [:0]const u8) Maybe(bun.StatFS) { if (Environment.isWindows) {