サブディレクトリの仕組み

概要

このセクションでは、gsutil でのサブディレクトリの仕組みについて説明します。 大半のユーザーは、これらの詳細を知らなくても、サブディレクトリを操作するコマンド(cp -r など)を使用できます。gsutil がサブディレクトリを処理する方法は多くの GUI / ウェブベースのツールと異なります(たとえば、"dir_$folder$" オブジェクトの作成など)。以下では、このような相違点、gsutil を使用した場合のコストとパフォーマンスについて説明します。

gsutil では、Cloud Storage サービスでサポートされる「フラット」な名前空間で階層型ファイルツリーを表現します。サービスから見れば、オブジェクト gs://your-bucket/abc/def.txt は名前に「/」文字を含む単なるオブジェクトです。「abc」ディレクトリはなく、そうした名前を持つ単なる 1 つのオブジェクトがあるだけです。次の図を見てください。

https://cloud.google.com/storage/images/gsutil-subdirectories.svg

gsutil では、バケット内のオブジェクトはこのような階層構造になっています。

gsutil では、ユーザーが想定する命名規則に合わせるため、さまざまなルールをファイルツリーに適用しています。たとえば、宛先の URL がオブジェクトなのか、オブジェクトのコピー先となるディレクトリのルートなのかを判定するために、次のルールを使用します。

  1. 宛先のオブジェクトが / で終了している場合、gsutil はディレクトリとして扱います。 たとえば、次のコマンドを実行します。

    gsutil cp your-file gs://your-bucket/abc/
    

    gsutil は、オブジェクト gs://your-bucket/abc/your-file を作成します。

  2. 宛先のオブジェクトが XYZ で、XYZ_$folder$ というオブジェクトが存在する場合、gsutil は XYZ をディレクトリとして扱います。たとえば、次のコマンドを実行します。

    gsutil cp your-file gs://your-bucket/abc
    

    abc_$folder$ というオブジェクトが存在する場合、gsutil はオブジェクト gs://your-bucket/abc/your-file を作成します。

  3. 複数のファイルを宛先の URL にコピーする場合、gsutil は宛先の URL をディレクトリして扱います。たとえば、次のコマンドを実行します。

    gsutil cp -r your-dir gs://your-bucket/abc
    

    gsutil は、gs://your-bucket/abc/your-dir/file1 というようなオブジェクトを作成します(file1 が元のディレクトリ your-dir の下にある場合)。

  4. 上記のどのルールにも該当しない場合、gsutil はバケットの一覧を作成し、操作対象の接頭辞が指定の文字列と一致しているかどうかを判定します。たとえば、次のコマンドを実行します。

    gsutil cp your-file gs://your-bucket/abc
    

    gsutil は、delimiter="/" と prefix="abc" を使用してバケットの一覧表示をリクエストします。次に、生成されたリストを検証し、gs://your-bucket/abc/ で始まるバケットのオブジェクトが存在するかどうか確認します。さらに、処理対象をオブジェクト名またはディレクトリ名として扱うかどうか判定します。この結果は作成するオブジェクトの名前に影響します。上記の確認で、abc ディレクトリが存在していると、オブジェクトの名前は gs://your-bucket/abc/your-file になりますが、それ以外の場合は gs://your-bucket/abc になります(詳細については、gsutil help cp の「名前の構成作成方法」をご覧ください)。

このルールベースのアプローチは、多くのツールが採用している、フォルダの存在をマーク付けするオブジェクト(dir_$folder$ など)を作成する方法とは逆の方法です。gsutil ではこうしたツールで使用されるいくつかの規則を理解しますが、UNIX コマンドと整合する命名を実施するためにこのようなマーカー オブジェクトを必要としません。

gsutil サブディレクトリの命名方法では、cp または mv コマンドを実行する前に余分なバケットリストを作成する必要があります。ただし、これらの一覧表示では、区切り文字と接頭辞パラメータで生成される結果を制限しているので、コストは比較的かかりません。また、gsutil が実行するバケット一覧の表示は cp / mv コマンドあたり 1 回だけです。このバケット一覧表示のコストは、転送されたすべてのオブジェクト間で償却されます(たとえば、クラウドにディレクトリの再帰コピーを実行する場合)。

宛先のサブディレクトリの命名に関する注意

このようなルールベースの方法で宛先パスの構造を特定している場合、バケット上に存在しないサブディレクトリにローカル ディレクトリのすべてのオブジェクトをアップロードするとどうなるでしょうか。

gsutil cp -r ./your-dir/* gs://your-bucket/new

ここで、your-dir の下にディレクトリ(dir1 と dir2)があるとします。このコマンドを最初に実行したときに、次のオブジェクトが作成されます。

gs://your-bucket/new/dir1/abc
gs://your-bucket/new/dir2/abc

これは gs://your-bucket/new が存在していないためです。同じコマンドを再度実行すると、今回は gs://your-bucket/new が存在するため、次のオブジェクトが作成されます。

gs://your-bucket/new/your-dir/dir1/abc
gs://your-bucket/new/your-dir/dir2/abc

この命名動作は不思議に感じるかもしれませんが、特に注意が必要になるのは gsutil uploads で再試行ループを処理する場合です。この場合、最初の実行ですべてのオブジェクトではなく、一部のオブジェクトしかコピーされない場合、次の実行で元のサブディレクトリの存在が検出されるため、上記のような命名問題が発生します。

この問題を回避するには、いくつかの方法があります。

1. gsutil rsync を使用します。rsync は Unix cp で定義されるディレクトリの命名規則を使用しません。宛先のサブディレクトリが存在するかどうかに関わらず、整合性のある命名処理が実行されます。

2. rsync で問題が解決しない場合には、宛先をサブディレクトリにするためにプレースホルダ オブジェクトを作成して、次のコマンドを実行します。

gsutil cp some-file gs://your-bucket/new/placeholder

この時点で、上記の gsutil cp -r コマンドを実行すると、gs://your-bucket/new がサブディレクトリして扱われます。このサブディレクトリに 1 つ以上のオブジェクトがある場合には、プレースホルダ オブジェクトを削除できます。このサブディレクトリに対する後続のアップロードでは、予期したとおりの命名処理が実行されます。