1 ポイント 投稿者 GN⁺ 2025-02-26 | 1件のコメント | WhatsAppで共有
  • Macの重複ファイル整理は通常、削除が前提だが、HyperspaceはAPFSクローンによって同じ内容のファイルを共有させ、ファイルを残したまま容量を取り戻す
  • APFSのcopy-on-writeクローンは、Finderの「複製」のように実データを書き直さず元ファイルと共有するため、大容量の複製もほぼ瞬時に完了する
  • 開発者はディスクがいっぱいになったことをきっかけに、内容は同じだがクローンではないファイルを見つけるPerlスクリプトを作成し、節約可能な容量が数十GBに達したことからアプリへ発展させた
  • アプリは無料でダウンロードしてスキャンし、節約可能な容量を確認できるが、実際に容量を回収するには有料課金が必要
  • 自分が作成または所有していないファイルを変更するためリスクは高いが、それだけ多くのMacユーザーに実用的な助けをもたらす可能性がある

APFSクローンでファイルを残したまま容量を回収

  • Hyperspaceは、同じ内容を持つファイル同士がクローン関係にない場合、それらをAPFSクローンに変換してディスク上のデータコピーを1つだけ共有させる
  • 既存のMac向け重複ファイルアプリはたいてい重複ファイルを見つけて削除することで容量を節約するが、Hyperspaceはファイルを削除せずに容量を回収する
  • APFSの主要機能にはポイントインタイムスナップショットとcopy-on-writeクローンがある
    • スナップショットはTime Machineバックアップをより安定的かつ効率的にするために使われる
    • copy-on-writeクローンは、ディレクトリエントリとファイル内容のあいだにある柔軟な構造に基づいている
  • Finderで「複製」コマンドを使ってファイルを複製すると、実際のファイル内容はコピーされず、元ファイルとデータを共有するクローンファイルが作られる
    • この仕組みにより、ファイルサイズに関係なくFinderでの複製はほぼ瞬時に完了する

リリース方法と開発メモ

  • 開発者は2024年末、自分のMacのディスクがいっぱいになったことをきっかけに、同じ内容を持つ非クローンファイルを探してクローンに変換するPerlスクリプトを書いた
    • このスクリプトは、Cで書かれたコマンドラインツールとSwiftで書かれたコマンドラインツールを呼び出す
    • 実行結果、節約可能な容量は数十GBと判明し、その後Macアプリへと発展した
  • HyperspaceはMac App Storeで提供されている
  • 開発面では、Hyperspaceは開発者にとって2本目のSwiftUI製Macアプリであり、SwiftUI life cycleを使った最初のアプリでもある
    • Swift 6を使った2本目のアプリでもある
    • 開発初期からSwift 6を使うほうが、すでにリリース済みのアプリをSwift 6へ移行するよりはるかに容易だった
    • Swift 6にはまだ粗い部分が多く、今後の改善に期待している
  • Hyperspaceは、HFS+からAPFSへの変換プロセスのように、アプリ自身が作成しておらず所有もしていないファイルを変更する
    • 開発者はこれを自分が作ったアプリの中で最も危険なアプリと呼んでいる
    • 同時に、最も多くの人にとって有用なアプリになる可能性があるとも考えている

1件のコメント

 
GN⁺ 2025-02-26
Hacker News の意見
  • 以前、同じことをするコマンドラインユーティリティ dedup を作ったことがある
    ドライランモードがあり、「賢く」最適なクローン元を選び、ハードリンクや他のクローンを理解し、メタデータを保持し、HFS 圧縮ファイルも正しく扱う
    自分のデータはまだ壊したことがないが、ファイルシステム系ツールの常として、利用は自己責任
    0 - https://github.com/ttkb-oss/dedup

    • スキャンだけ試して重複排除はまだしていない段階で書くと、ディスクイメージ、プログラムバイナリ、中間表現を扱う 7.6GB の作業領域では、かなり差が見える
      Hyperspace は基本的に全ファイルをスキャンせず、許可リストにあるファイルだけを見ており、ファイル内容を理解する必要がある構造のように見える。エンドユーザーの立場ではテキストファイルとソースコードファイルの違いをどう区別しているのか分からず、デフォルトのスキャンでは 360MB だけが重複排除対象として見つかったが、全ファイルを許可すると 842MB に増えた
      デフォルトでは 100KB 未満のファイルもスキャンせず、サイズ制限をオフにして全ファイルを許可すると 1.1GB まで増えた。全ファイル・サイズ制限なしの条件で、Hyperspace は 68,874 個中 67,309 個をスキャンし、dedup は 67,426 個をスキャンした
      Hyperspace は 29,522 個のファイルが重複排除可能だとし、dedup は 29,447 個を見つけた。すでに重複排除済みのファイルが 76 個あるので 1 個差が出ているが、正確な原因は分からない
      スキャン時間は Hyperspace が約 50 秒、dedup が 14 秒だった。Hyperspace はファイルシステムをスキャンした後に重複計算を行い、その次に重複排除をするようだが、なぜ前の 2 段階を一緒にしないのか分からない。私はスキャン中にファイルシステムのメタデータをキューに入れ、並列で重複計算を始めるようにしており、大半は fts_read でディレクトリをたどる際に「タダで」得られるサイズ情報だけで不一致を弾ける
      Hyperspace は 1.1GB 節約可能だとし、dedup は 1.04GB と、すでに節約済みの 882MB を見つけた。Hyperspace を買うつもりはないので実際の重複排除時間やメタデータ保持、変なファイルの扱いまでは分からないが、dedup はスキャンと重複排除を合わせて 31 秒かかった
      dedup で重複排除した後でも、Hyperscan はまだ重複排除可能なファイルが 2 個あると判断した。Hyperspace も複数のハードリンクが張られたファイル、空ファイル、dedup が検査する各種例外は扱っているようだ。ACL やその他属性の保持は課金なしではテストできないが、strings を見る限り処理しているように見え、HFS 圧縮は厄介な境界ケースなので、Hyperspace のスキャンがどう扱うかはまだ確認できていない
    • Postgres の開発ディレクトリのように、ほぼ同じファイルが多い場所で走らせてみたところ、約 1.7GB 節約できた
      プロジェクトにライセンスがないので、可能なら希望するライセンスを付けてもらえるとありがたい。インストール手順を少し改善しようとしてプルリクエストも作った: https://github.com/ttkb-oss/dedup/pull/6
    • さっき使ってみたが、うまく動作した。実際に特定のファイルタイプ、特に node_modules の中に重複がどれほど多いかを見て、ようやくこの手法の可能性に気づいた
      特定のサブディレクトリだけを見ても、ある JS ファイル 50 個のコピーを 1 つに置き換えるようなことは珍しくなかった。ただし「pre-release」で GitHub のスターも少なめなので、こうしたツールはバグがあるとかなり怖いだけに、安定性が気になる
    • ドキュメントが素晴らしく、make がほぼ即座に終わる点も印象的だった
    • 代替ツールの一覧は https://news.ycombinator.com/item?id=38113396 のコメントを見るとよい
      以前 https://github.com/sahib/rmlint を使っていたが、特に不満はなかった
  • 「Hyperspaceが他のすべてのアプリやmacOS自体と協調して、ファイル置き換えに安全なタイミングを調整する方法もなく、そのファイルを強制的に排他的に制御する方法もない」という部分を見て、なぜファイルシステム自体がバックグラウンドで似たような重複排除プロセスを走らせないのか気になった
    その程度の抽象化レイヤーなら、こうした安全性の問題を管理できそうに思えるが、APFS内部で自動的に起きるとどんな欠点があるのだろうとも思う

    • ZFSではRAMを大量に使う。ZFSがブロックレベルで処理するため、新しいブロックが書き込まれるたびに比較対象となる多数のブロックを追跡しなければならないからのようだ
      ファイルレベルで実装すればリソース使用量は減るかもしれないが、実装がより単純になるのか複雑になるのかは分からない。また、大きなファイルで1バイトだけ変更しても、ファイルシステムがそのファイルを再度複製しなければならず、ディスク活動が大量に発生するという点は直感的ではないかもしれない
    • ブロックストレージ装置では、こうしたことを圧縮と一緒によく行う。もちろん、ファイルシステムが装置へ送るブロックを暗号化すると失敗する
      このレイヤーで重複排除を行うと、複数のファイルシステムにまたがって重複排除できるので都合がよい。例えば、同じOSファイルを持つシステムが1000台あるならストレージ容量を大幅に節約でき、違いはホストキーやホスト名のようなシステムごとの設定程度であることが多い。単一のファイルシステムでは、こうした共通性に気付けない
      ただし、重複排除によって使用頻度の高いファイルの複製数が減ると問題になる。先ほどの例で1000台を同時に起動すると、カーネルイメージにものすごいI/O負荷がかかる可能性がある
    • Linuxでは、これがbtrfsとXFSで使われる標準の重複排除API
      指定した範囲の集合をOSに丁重に重複排除してほしいと頼むと、OSが範囲をロックし、実際に同一かどうかを検証してから重複排除してくれる。各範囲で何バイトが重複排除されたかもフィールドとして返ってくるので、ユーザー空間のプログラムがファイルを壊す余地はない
    • ZFSは実際にこうしたことを行う: https://www.truenas.com/docs/references/zfsdeduplication/
    • Windows ServerもNTFSとReFSボリュームでこの機能を提供している
      Hyper-V VMを載せたReFSでかなり使ったことがあり、効果は抜群だった。当時はWindows Server 2016/2019が混在したVMが大半だったが、ストレージ使用量を約**45%**削減できた
  • スキャンは無料で行ってメリットがあるか確認し、実際の結果に対してだけ支払うモデルが気に入った
    自分もファイルをため込みがちなので試してみたら、7GB回収可能と出たが、自分にとってはその程度では支払うほどではなかった。それでもこういうツールがあるのは良い

    • ポッドキャストでこのモデルを説明したことがある。多くのユーザーはこれを買って一度実行し、数GBを節約して終わりになるだろうから、サブスクリプションはあまり筋が通らない
      そもそも1か月に、まったく同じ重複ファイルをうっかりどれだけ作るというのか?
      実際に頻繁に使う人向けにサブスクリプションや買い切りの選択肢もあるが、多くの人にとっては、限られた期間だけ使える一回限りのアプリ内課金がかなり合理的だ。そしていつでも無料で再実行して、また支払うほどたまったか確認できる
    • こうした重複排除アプリの価値は、自分にとっては容量節約というより重複ファイルを残さないことに近い
      とてつもない量を作るわけではないが、一部または全部を合わせると大きな重複ファイルが生まれることがある。たいていは、ハードドライブの復旧結果を別の場所にあるファイルと突き合わせる必要があったり、散らかったダウンロードフォルダを整理済みの保存先と突き合わせる必要があったりする妙な状況で起きる
      例えば、Time Machineバックアップが、自分では記録があることすら知らず、ずっと昔に失ったと思っていたファイルの古いバージョンを押し出してきたことがあるが、ディレクトリ名は壊れていて、内容もある程度難読化されていた。数字名のディレクトリが何千もあり、その中には保管したいファイルがあるかもしれないが、すでに持っているのか、どこにあるのかがまったく構造化されておらず分かりにくい。逆に、同じビルドシステムのテキストファイルが1つ入っているだけという場合も多く、そういうものは当然捨てられる
    • 10年前なら、ほとんどのソフトウェアがこういう形だったと覚えている自分は、そんなに年を取ったのかと思う
      人々はすでにサブスクの罠に慣れすぎていて、これを新しいモデルのように感じているのだろうか
    • この価格モデルは本当に気に入っている
      他のソフトウェアでもこうしやすければよいのだが、たいていは価値が見える前に学習曲線が立ちはだかっている
    • キャンセルを覚えておかなければならない「無料体験」よりずっと新鮮だ
      ちょっとしたコツとして、そういう体験版にはロックできるバーチャルカードを使うと、キャンセルを忘れても決済を防げる。ところで、Webサイトで実際のライセンス価格を見つけた人はいるのだろうか
  • アプリが2つのファイルが同一かどうかを判定するのに、どんなアルゴリズムを使っているのか気になる
    ハッシュ、ビット単位の比較など興味深い方法は多いが、それぞれ欠点もある。ファイルが非常に多い場合、最良の方法は何だろう

    • Siracusaが正確に何をしているのかは分からないが、推測はできる
      各候補ファイルごとに、他の候補ファイルと同じか確認するための「キー」が必要だ。ファイルは数百万個あるかもしれないので、キーは小さく素早く生成できる必要があるが、同時に偽陽性があってはならない
      今なら明らかな答えは、ファイル内容のSHA256ハッシュだ。非常に高速で、サイズも32バイトとそれほど大きくなく、偽陽性や衝突の確率は、実際に遭遇する前に世界が終わるほど低い。SHA256はこの用途では事実上の標準なので、別のことをしていたらかなり驚くだろう
    • https://en.wikipedia.org/wiki/Venti_(software)を思い出した
      ハッシュを重複排除に使う内容アドレス指定ファイルシステムで、ハッシュは書き込み時に計算されるため、性能コストが分散される
    • すべてのファイルの先頭1024バイトをハッシュし、衝突があった場合だけ次に進むだろう
      そうすれば大きなファイル全体をハッシュする必要がなく、同じハッシュを持つファイルだけを追加で見ればよい
  • AppleはAPFSのクローン機能を使えるように、-cフラグをサポートする修正版の**cpコマンド**も同梱している

    • 使っているcpがそれをサポートしていないなら、Pythonから呼び出すこともできる
      例えば import Foundation; Foundation.NSFileManager.defaultManager().copyItemAtPath_toPath_error_(...) のような形だ
  • ファイルAが2か所にあり、これを実行した後で A_0 を変更した場合、A_1 も一緒に変わるのか、それとも A_0 の新しい状態だけが実体化されて A_1 はそのまま残るのかが気になる

  • WWDC 2017でAppleがAPFSを発表する前、iOS 10.xアップデートの一部として、すべてのiPhoneを密かにAPFSへ試験的に変換し、その後HFS+へ戻していたというくだりが目を引いた
    ファイルシステムの変更が失敗した場合、どうやって元に戻せるのかが気になる。コードを十分に検証することはできるだろうが、何か問題が起きたら取り消し不能に見える

    • 記憶が正しければ、HFS+からAPFSへのマイグレーションはデータブロックに触れずに可能で、APFSのメタデータブロックとスーパーブロックをディスクへ並行して書き込む
      Appleのテストマイグレーションでは、APFSスーパーブロックの作成まで含めて全体のマイグレーションを実行しつつ、HFS+スーパーブロックをAPFSスーパーブロックで恒久的に置き換えるコミットの直前で止めていた。戻すときは、生成されたAPFSスーパーブロックとメタデータブロックだけを「単に」片付ければよかった
    • 発表の該当部分を見たが [0]、整合性テストとして行ったという以外、詳細はほとんどない
      本番環境でいろいろ壊してきた身としては、こんな大規模なマイグレーションを実行しろと言われたら、ボタンを押せるか分からない
      [0] https://www.youtube.com/watch?v=IcyaadNy9Jk&t=1670s
    • 想像力が足りないように思う。これはAppleだけが持つ王冠の宝石のような技術ではない
      オープンソースの世界にもextファイルシステムをbtrfsへ変換するツールがあり、(1) ロールバック可能で、(2) btrfsファイルシステムを使っている間も元のextファイルシステムをマウントできる
  • 物語から始めて問題へと絞り込み、その解決策が問題を魔法のように解決する様子を見せている
    優れたマーケティングの非常に良い例だ

  • 巨大なNodeJSプロジェクトフォルダにかけてみたが、8.1GBのフォルダで1GBしか節約できないと表示された
    ユーザーのホームフォルダまで含めて再実行したところ、731K個のファイル、127K個のフォルダ、2,755個の対象ファイルで、合計1.3GBの節約にとどまった。NodeJSフォルダだけを対象にしたときより300MB増えた程度だ
    SystemとLibraryもスキャンしようとしたが、権限の問題で拒否された。パッケージマネージャーにpnpmを使っているので、すでにディスク使用量はほぼ最適に近いのだと思う
    アイデアは素晴らしいが、現在の価格では正当化しにくく、月に1回程度バックグラウンドプロセスとして走る形ならよさそうだ

    • 8.1GBのうち1GBなら、使っている容量の 12%が無駄 になっていたということでは? 読み違えているのかもしれない
    • pnpmはnpmのドロップイン代替を目指しており、自動で 重複排除 を行う
    • macOSには 封印されたボリューム があるため、SystemとLibraryで権限エラーが見える
      https://support.apple.com/guide/security/signed-system-volum...
    • 自分で試す時間はなかったが、App Storeのスクリーンショットには、考慮対象にする 最小ファイルサイズのオプション がはっきり見える
      比較バッファを減らすために導入したもののようだが、node_modules内のファイルがこのサイズ未満で、考慮されなかった可能性がある
    • 価格がいくらなのか分からない。どこにも公開されていないようだ
  • 同じ内容のファイルを ハードリンク に置き換える、似ているがより単純なスクリプトを作ったことがある
    主な動機はPythonの仮想環境内のパッケージだった。似たようなパッケージをインストールしておくことが多く、バージョンが違っても多くのファイルはなお一致する。Numpy、PyTorch、TensorFlowのような一部のパッケージはかなり巨大なので、ディスク容量を相当に節約できた
    https://github.com/albertz/system-tools/blob/master/bin/merg...

    • これはハードリンクやシンボリックリンクを使うのではなく、ファイルシステムの コピーオンライトのクローン 作成機能を使うもの [1]
      [1] https://en.wikipedia.org/wiki/Apple_File_System#Clones
    • uvはこれをデフォルトにしている
      poetry、hatch、pdmのような他のツールもそうだと思うが、細かい挙動はあまり使っていないのでよく分からない