active: true
derived: false
gherkin: |
  Feature: S3Storage
    Scenario: Storing large blobs in Amazon S3
      Given an S3Storage instance configured with a valid URI
      When data is saved to the storage
      Then it is uploaded to S3, using multipart upload for data exceeding 5GB
groups:
- STORE
header: |
  S3Storage
level: '2.10'
links:
- ARCH004: gR_7wx5EpD_LA3s4JJTJmD1-WOKDjlo563zos3pn-aE=
normative: true
ref: ''
reviewed: 2R4q63eIDFBXPgHQROfP1lIXCW6a0mZjzAVTyK0oLQc=
text: |
  ## インターフェース

  ```python
  class S3Storage(BlobStorageMaintenable):
      def __init__(self, s3_uri: str, s3_opts: dict | None = None): ...
  ```

  ## 振る舞い

  ### URIベースの管理
  - `s3://bucket/prefix/key.bin` 形式のURIをロケーション識別子として使用する。

  ### 大容量対応 (`save`)
  - `boto3.upload_fileobj` を使用。5GBを超えるデータに対しては、自動的にマルチパートアップロードに切り替えられ、PutObjectの制限を回避する。

  ### 高速なメタデータ取得 (`get_mtime`)
  - `head_object` を使用し、データ本体をダウンロードせずに最終更新時刻（LastModified）を取得する。

  ## パラメータ詳細

  | 設定 | 内容 |
  |---|---|
  | `s3_uri` | `s3://my-bucket/my-prefix` 形式 |
  | `s3_opts` | `boto3.client('s3', **s3_opts)` に渡される設定 |

  ## エラーハンドリング

  - **ライブラリ不在**: `boto3` がインポートできない環境でインスタンス化を試みると `ImportError` を送出
  - **ネットワークエラー**: `botocore.exceptions.ClientError` をキャッチし、状況に応じて `CacheCorruptedError` に変換

  ## エッジケース

  - **リージョン不一致**: S3クライアントの設定とバケットのリージョンが異なる場合の動作は Boto3 のデフォルト設定に依存
  - **削除の冪等性**: S3 は存在しないオブジェクトの削除要求に対してエラーを返さないため、常に成功として扱う

  ## 設計判断

  クラウドネイティブな環境において、キャッシュデータをS3等のオブジェクトストレージに分散保存し、複数インスタンス間で安全に共有できるようにするため。
