Class LazyBigtableDataClient

java.lang.Object
io.github.flink.gcp.connector.bigtable.LazyBigtableDataClient
All Implemented Interfaces:
Serializable

@Internal public final class LazyBigtableDataClient extends Object implements Serializable
A BigtableDataClient built on first use and closed once, held by a seam implementation that travels in the job graph.

The seams that read through the data client — the scan source's row-stream opener and row-key sampler, and the change-stream source's opener — differ in the one call they make and share everything around it: the settings they build, the provider their owner hands them, the lazy construction and the close. That shared half lives here so that no seam owns a private copy of client lifecycle code.

No key-file path travels here. The runtime component that owns the seam loads one provider for every client family it owns and pushes it in, so this holder never loads a second one.

The client is transient because the reader-side holders, DataClientRowStreamOpener and DataClientChangeStreamOpener, are serialized into the job graph — the enumerator-side holder is not any more, since docs/adr/0128 mints one sampler per enumerator, so for that owner the marker is inert rather than load-bearing. It is volatile because the thread that builds it may not be the thread that closes it, and built under this object's monitor rather than a lock field, because a lock field would have to travel in the job graph too. Which threads those are depends on the seam: a scan reader's split fetchers open streams from their own threads while close() runs on the task thread once the fetchers are down; an enumerator samples from the executor SplitEnumeratorContext#callAsync hands the work to while close() runs on the coordinator thread; the change-stream reader has no fetcher pool and opens and closes on its one task thread, inheriting the guarding rather than needing it.

The holder does not lease a client returned by get(TableDestination). Synchronizing the return would still let close() run before the caller starts its operation, while holding the monitor for an operation would make coordinator teardown wait for a service round trip. Each owner therefore supplies the operation lifecycle: the scan reader stops its fetchers before closing the opener, the change-stream reader cancels its active reads first, and an enumerator ignores a sampling completion that arrives after teardown.

See Also:
  • Constructor Details

    • LazyBigtableDataClient

      public LazyBigtableDataClient(String owner, @Nullable String appProfileId, @Nullable EmulatorEndpoint emulatorEndpoint)
      Creates the holder.
      Parameters:
      owner - how the holder names its seam in the closed-before-use failure, for example "row stream opener"
      appProfileId - the application profile to route through, or null for the instance's default
      emulatorEndpoint - the emulator endpoint (plaintext, no credentials), or null for production Bigtable
  • Method Details

    • get

      public com.google.cloud.bigtable.data.v2.BigtableDataClient get(TableDestination table) throws IOException
      Returns the client, building it on first use.
      Throws:
      IOException
    • settings

      @VisibleForTesting public com.google.cloud.bigtable.data.v2.BigtableDataSettings settings(TableDestination table) throws IOException
      Builds the client settings.

      The method is public so module tests can inspect the mapping directly. That direct test access deliberately performs no lifecycle check: holder tests use it after close to observe credential clearing without constructing a client. Production operations reach the method only through get(TableDestination), which refuses use after close.

      Throws:
      IOException
    • useCredentials

      public void useCredentials(@Nullable com.google.api.gax.core.CredentialsProvider credentials)
      Takes the provider the seam's owner loaded, or null to keep ADC.

      The owner supplies credentials before first use and before close. Injection waits for any client construction already holding this object's monitor.

      Throws:
      IllegalStateException - if the holder is already closed
    • close

      public void close() throws IOException
      Closes the client if one was built, clears credentials, and refuses later use.
      Throws:
      IOException