Skip to content

Build1 publisher3 min readPublished

Collapsing three copies into one Iceberg table moves the conflict into an HTTP 409

A GCP walkthrough put Spark, Trino and BigQuery on the same orders table through Google's Iceberg REST catalog. The 409 ConflictException it logged is the part of the demo a production pipeline has to plan for.

The Engineer · Build desk

Illustration accompanying Collapsing three copies into one Iceberg table moves the conflict into an HTTP 409

What happened

  • A dev.to walkthrough on Google Cloud had Spark commit through the Iceberg REST catalog, Trino read and write the same table, and BigQuery run DML on it, all against one copy of the files.
  • The run captured a genuine optimistic-concurrency rejection, an HTTP 409 ConflictException, and published the full logs in the repository's evidence/ folder.
  • Authorization runs through Workload Identity, using the workload's own execution identity in place of downloaded service account .json key files.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • decision Adding a third or fourth writer to one table becomes a scheduling question, because overlapping commits now fail at the catalog instead of blending in storage. Write windows and backoff have to be settled before the demo becomes a pipeline.
  • cost One copy ends two of the three storage charges on the same terabytes. The spend that replaces it is engineering time on conflict handling in every engine that writes.
  • constraint IAM bindings, Spark catalog config and runbooks all key on biglake strings, so an estate-wide search for the new product name will not surface the resources under management.
  • capability Trino gets a write path to the same table as BigQuery, so an ad-hoc engine can correct data directly instead of filing a request with whoever owns the warehouse copy.

An Iceberg commit does not edit the table in place. The writer lays down new Parquet and new metadata files, then asks the catalog to make its version the current one. The REST catalog is the single arbiter of which version is current [3], and the transaction guarantee is all-or-nothing: the whole write lands or nothing changes [4]. Two writers that both started from the same snapshot both ask, the catalog moves the pointer once, and the second gets HTTP 409 ConflictException [2].

The same write-up describes the failure this replaces. Keep the data as loose Parquet in a storage folder, let two processes write at once, and one can silently overwrite the other [6]. Updating a single row in a Parquet file means rewriting the whole file [6].

Contention rates are a property of your workload. The setup is one retail orders table, orders_iceberg, in Cloud Storage with three applications on it [11], and the write-up does not report table size, commit rate, how many commits collided, or whether the losing writer retried [13]. For a 409 rate measured here to say anything about a production pipeline, the overlap would have to match: the same table, the same window, writers that do not coordinate with each other. The run does show that all three engines can commit through the one catalog [1], and that the rejection comes back as a status code a client can branch on [2].

After a 409, the losing writer cannot resend the same commit. Its base version is no longer current, so it has to re-read the current snapshot and redo the work against that [3]. Time travel means the older snapshots are still queryable, because Iceberg keeps the version history [5].

Only the prose got the new product name. Google renamed BigLake to Lakehouse for Apache Iceberg [7], and the identifiers still spell biglake: the API endpoint, the gcloud subcommand, the gcp.biglake.* table properties, the blirc-* managed service account, CATALOG_TYPE_BIGLAKE, and the bl:// warehouse scheme [9]. Anyone searching Google's docs for "Lakehouse" and their own Terraform for the same word gets two different answers.

I like the authorization design. Access goes through Workload Identity, using the workload's own execution identity, so there is no service account .json key file to download and rotate per engine [10]. The catalog itself is the open Iceberg REST standard, with read and write interoperability across BigQuery, Google's managed Spark service, and OSS engines including Spark, Trino and Flink [8].

The billing case is simple. Three teams keeping three copies paid double or triple storage on the same terabytes and watched one copy update while the others kept the old value [12]. Consolidating to a single copy removes two of those three storage charges [14].

What to watch

  • Whether Google documents retry and backoff semantics for commits through the Lakehouse Iceberg REST catalog, or leaves them to each engine's client.
  • Any rename of the biglake API endpoint, CLI or catalog type: existing scripts and IAM bindings key on those strings.
  • How the Workload Identity path applies to engines such as Trino running outside a Google Cloud execution identity.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories