Package biopb.tensor

Class TensorFlightClient

java.lang.Object
biopb.tensor.TensorFlightClient
All Implemented Interfaces:
AutoCloseable

public class TensorFlightClient extends Object implements AutoCloseable
Client for accessing tensors from a TensorFlightServer. This client uses Apache Arrow Flight to discover data sources, request logical read plans, and fetch chunk payloads from a TensorFlightServer. It supports multifield acquisitions where tensors within a source have different shapes. The Java client returns lazy cell-backed images when the logical Flight endpoint layout matches the descriptor chunk grid. In that case, imglib2's internal cell cache is the primary cache for repeated reads.

A tensor is identified by its globally-unique array_id (the tensor identity policy; see the top of proto/biopb/tensor/descriptor.proto): either source_id for a single-tensor source or source_id/field for a multi-tensor one. The array_id-first methods (getTensor(String), getDescriptor(String), getPhysicalScale(String)) take that one identifier; the older (sourceId, tensorId) overloads remain available. Usage:

 TensorFlightClient client = new TensorFlightClient("localhost:8815");

 // List data sources (each may contain multiple tensors)
 Map<String, DataSourceDescriptor> sources = client.listSources();

 // Access a tensor by its array_id ("source_id" or "source_id/field")
 RandomAccessibleInterval<UnsignedByteType> arr = client.getTensor("my-source/tensor-0");
 long[] pos = { 10, 20, 30 };
 UnsignedByteType pixel = arr.getAt(pos);
 client.close();
 
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final class 
    Per-dimension physical pixel size + unit for a tensor, as returned by getPhysicalScale(java.lang.String).
  • Constructor Summary

    Constructors
    Constructor
    Description
    TensorFlightClient(String host, int port)
    Create a new TensorFlightClient.
    TensorFlightClient(String host, int port, long cacheBytes)
    Create a new TensorFlightClient with custom cache size.
    TensorFlightClient(String host, int port, long cacheBytes, String token)
    Create a new TensorFlightClient with authentication token.
    TensorFlightClient(org.apache.arrow.flight.Location location)
    Create a new TensorFlightClient for an Arrow Flight location.
    TensorFlightClient(org.apache.arrow.flight.Location location, long cacheBytes)
    Create a new TensorFlightClient for an Arrow Flight location.
    TensorFlightClient(org.apache.arrow.flight.Location location, long cacheBytes, String token)
    Create a new TensorFlightClient for an Arrow Flight location with authentication.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
     
    long
    Get the cache size in bytes.
    Fetch one tensor's TensorDescriptor by its globally-unique array_id.
    org.apache.arrow.flight.Location
    Get the Flight server location.
    Per-dimension physical pixel size + unit for a tensor.
    Get source-level OME/vendor metadata as a map.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String arrayId)
    Get a RandomAccessibleInterval for a tensor by its globally-unique array_id.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String arrayId, long[] scaleHint, String reductionMethod)
    Get a RandomAccessibleInterval for a tensor (by array_id) with scaled reads.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String arrayId, SliceHint sliceHint)
    Get a RandomAccessibleInterval for a tensor (by array_id) with a slice hint.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String arrayId, SliceHint sliceHint, long[] scaleHint, String reductionMethod)
    Get a RandomAccessibleInterval for a tensor (by array_id) with all options.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String sourceId, String tensorId)
    Get a RandomAccessibleInterval for a tensor within a data source.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String sourceId, String tensorId, long[] scaleHint, String reductionMethod)
    Get a RandomAccessibleInterval for a tensor with scaled read options.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String sourceId, String tensorId, SliceHint sliceHint)
    Get a RandomAccessibleInterval for a tensor with slice hint.
    <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    getTensor(String sourceId, String tensorId, SliceHint sliceHint, long[] scaleHint, String reductionMethod)
    Get a RandomAccessibleInterval for a tensor with all options.
    getTensorAsPb(String sourceId, String tensorId, SliceHint sliceHint, long[] scaleHint, String reductionMethod)
    Get a SerializedTensor protobuf for cross-process transfer.
    Get the authentication token.
    Get upload status for a registration-first SerializedTensor handle.
    Get upload status for a writable source.
    Check server health status via Flight action.
    List available data sources.
    org.apache.arrow.vector.VectorSchemaRoot
    Execute SQL query against server's source metadata database.
    resolve(String sourceId)
    Resolve an unresolved source and return its full DataSourceDescriptor.
    static <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>>
    net.imglib2.RandomAccessibleInterval<T>
    tensorFromPb(SerializedTensor pb, long cacheBytes)
    Reconstruct a lazy RandomAccessibleInterval from SerializedTensor protobuf.
    waitForUploadReady(SerializedTensor pb, long timeoutMillis, long pollIntervalMillis)
    Poll upload status until a registration-first SerializedTensor is READY.
    waitForUploadReady(String sourceId, long timeoutMillis, long pollIntervalMillis)
    Poll upload status until the source reports READY.
    warm(String sourceId)
    Hydrate-ahead: ask the server to recall all of a resolved multi-file source's member files, so later reads are warm and never stall.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • TensorFlightClient

      public TensorFlightClient(String host, int port)
      Create a new TensorFlightClient.
      Parameters:
      host - Server host
      port - Server port
    • TensorFlightClient

      public TensorFlightClient(String host, int port, long cacheBytes)
      Create a new TensorFlightClient with custom cache size.
      Parameters:
      host - Server host
      port - Server port
      cacheBytes - Maximum cache size in bytes
    • TensorFlightClient

      public TensorFlightClient(String host, int port, long cacheBytes, String token)
      Create a new TensorFlightClient with authentication token.
      Parameters:
      host - Server host
      port - Server port
      cacheBytes - Maximum cache size in bytes
      token - Bearer token for authentication (null disables auth)
    • TensorFlightClient

      public TensorFlightClient(org.apache.arrow.flight.Location location)
      Create a new TensorFlightClient for an Arrow Flight location.
      Parameters:
      location - Flight server location
    • TensorFlightClient

      public TensorFlightClient(org.apache.arrow.flight.Location location, long cacheBytes)
      Create a new TensorFlightClient for an Arrow Flight location.
      Parameters:
      location - Flight server location
      cacheBytes - Maximum cache size in bytes
    • TensorFlightClient

      public TensorFlightClient(org.apache.arrow.flight.Location location, long cacheBytes, String token)
      Create a new TensorFlightClient for an Arrow Flight location with authentication.
      Parameters:
      location - Flight server location
      cacheBytes - Maximum cache size in bytes
      token - Bearer token for authentication (null disables auth)
  • Method Details

    • getLocation

      public org.apache.arrow.flight.Location getLocation()
      Get the Flight server location.
      Returns:
      Location used for this client
    • getToken

      public String getToken()
      Get the authentication token.
      Returns:
      Bearer token (null if no authentication)
    • getCacheBytes

      public long getCacheBytes()
      Get the cache size in bytes.
      Returns:
      Maximum cache size for cell images
    • listSources

      public Map<String,DataSourceDescriptor> listSources() throws IOException
      List available data sources. Each data source may contain multiple tensors (for multifield acquisitions where tensors have different shapes). The returned DataSourceDescriptor contains full tensor metadata (shape, dtype, chunk_shape) for all tensors. Results may be truncated if server has max_list_flights_results configured. Check returned map size vs total_sources in schema metadata for truncation info.
      Returns:
      Map of source_id to DataSourceDescriptor
      Throws:
      IOException
    • querySources

      public org.apache.arrow.vector.VectorSchemaRoot querySources(String sql) throws IOException
      Execute SQL query against server's source metadata database. Returns Arrow VectorSchemaRoot with query results. Schema metadata may contain "total_sources" key if result was truncated. The server-side metadata database is mandatory (biopb/biopb#225), so any standard tensor-server supports this. Only an embedded server explicitly constructed without a metadata database rejects the query.
      Parameters:
      sql - SQL query (e.g., "SELECT source_id FROM sources WHERE source_url LIKE '%plate%'")
      Returns:
      VectorSchemaRoot with query results (caller must close)
      Throws:
      IOException - If query fails or the server has no metadata database attached Example:
                           VectorSchemaRoot result = client.querySources("SELECT source_id, source_type FROM sources");
                           System.out.println("Found " + result.getRowCount() + " sources");
                           result.close();
                           
    • getSourceMetadata

      public Map<String,Object> getSourceMetadata(String sourceId) throws IOException
      Get source-level OME/vendor metadata as a map.
      Parameters:
      sourceId - Source identifier
      Returns:
      The source's metadata map, or an empty map if it carries none
      Throws:
      IllegalArgumentException - if the source is unknown
      IllegalStateException - if the source is unresolved (cloud / synced-folder) -- call resolve(java.lang.String) first
      IOException
    • resolve

      public DataSourceDescriptor resolve(String sourceId) throws IOException
      Resolve an unresolved source and return its full DataSourceDescriptor.

      An unresolved source is catalogued by URL only -- its shape/dtype/field list are unknown until first access (it lists with data_resident false and an empty tensors). The canonical case is a cloud / synced-folder ("Files-On-Demand") source.

      Resolving asks the server to hydrate it. For a dehydrated placeholder this downloads the whole file -- a recall that can take minutes, consume local disk, and fail when offline -- then reads its real shape, dtype, and field list. This is the heavyweight, consenting operation that catalog browsing (listSources() / querySources(java.lang.String)) deliberately avoids; call it only when you intend to read the data. Afterwards getTensor(java.lang.String) and friends work normally. Idempotent.

      Parameters:
      sourceId - The source to resolve (e.g. "onedrive_a3f2")
      Returns:
      The full DataSourceDescriptor with every tensor/field enumerated
      Throws:
      IOException - If the action fails or the server returns no descriptor
    • warm

      public WarmProgress warm(String sourceId) throws IOException
      Hydrate-ahead: ask the server to recall all of a resolved multi-file source's member files, so later reads are warm and never stall.

      resolve(java.lang.String) populates a source's metadata but, for a multi-file cloud source (zarr / ome-zarr / ndtiff / tiff-sequence / micromanager), leaves the bulk pixel data dehydrated -- each member file then recalls one-at-a-time, slowly, the first time a read touches it. This walks the source directory server-side and reads every file to force the sync engine's recall; no pixels cross the wire, only progress. It is idempotent (already-resident files are cheap local reads) and a no-op for a single-file source (resolve already recalled it).

      Parameters:
      sourceId - The (already-resolved) source to warm.
      Returns:
      The terminal WarmProgress snapshot (files/bytes made resident; filesTotal == 0 for a no-op source).
      Throws:
      IOException - If the action fails, the server is too old to support the warm action, or it returns no terminal status.
    • getDescriptor

      public TensorDescriptor getDescriptor(String arrayId)
      Fetch one tensor's TensorDescriptor by its globally-unique array_id.

      A tensor is identified by its array_id alone (see the tensor identity policy at the top of proto/biopb/tensor/descriptor.proto), so this takes that one identifier rather than a (sourceId, tensorId) pair. Works even when the source is beyond the (truncatable) listSources() cap, and the result is cached. A bare source_id (single-tensor source, or to anchor on a multi-tensor source's default/first tensor) is accepted. To enumerate ALL tensors/scenes of a source, use listSources().get(sourceId).getTensorsList() -- NOT this method.

      This is a cheap probe -- it does NOT resolve. On an unresolved (cloud / synced-folder) source it raises an error pointing at resolve(java.lang.String).

      Parameters:
      arrayId - Globally-unique tensor id, e.g. "zarr_a3f2" or "aics_7f3/Image:0"
      Returns:
      The TensorDescriptor for that tensor
    • getPhysicalScale

      public TensorFlightClient.PhysicalScale getPhysicalScale(String arrayId)
      Per-dimension physical pixel size + unit for a tensor.

      Returns a TensorFlightClient.PhysicalScale whose scale and unit arrays are aligned with the tensor's dim_labels (source axis order), or null when no physical sizes are known (an older server, or a format that carries none).

      physical_scale/physical_unit are TensorDescriptor fields the server fills on every GetFlightInfo (issue #31), so this reads the descriptor a prior getTensor(java.lang.String) already cached -- no extra RPC when it is cached, and it never requests the opt-in metadata_json field on that same descriptor. (Contrast getSourceMetadata(java.lang.String), which forces with_metadata to ship the whole OME tree; do not dig physical sizes out of that -- this is the compact projection meant for display scale.)

      Parameters:
      arrayId - Globally-unique tensor id (source_id or source_id/field). A bare source id anchors on the source's default (first) tensor.
      Returns:
      A PhysicalScale, or null if no physical scale is known
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String arrayId)
      Get a RandomAccessibleInterval for a tensor by its globally-unique array_id.
      Type Parameters:
      T - The pixel type
      Parameters:
      arrayId - Globally-unique tensor id (source_id or source_id/field)
      Returns:
      RandomAccessibleInterval containing the requested tensor
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String arrayId, SliceHint sliceHint)
      Get a RandomAccessibleInterval for a tensor (by array_id) with a slice hint.
      Type Parameters:
      T - The pixel type
      Parameters:
      arrayId - Globally-unique tensor id (source_id or source_id/field)
      sliceHint - Optional slice hint
      Returns:
      RandomAccessibleInterval containing the requested tensor
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String arrayId, long[] scaleHint, String reductionMethod)
      Get a RandomAccessibleInterval for a tensor (by array_id) with scaled reads.
      Type Parameters:
      T - The pixel type
      Parameters:
      arrayId - Globally-unique tensor id (source_id or source_id/field)
      scaleHint - Per-dimension scale factors
      reductionMethod - Requested reduction method
      Returns:
      RandomAccessibleInterval containing the requested tensor
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String arrayId, SliceHint sliceHint, long[] scaleHint, String reductionMethod)
      Get a RandomAccessibleInterval for a tensor (by array_id) with all options.
      Type Parameters:
      T - The pixel type
      Parameters:
      arrayId - Globally-unique tensor id (source_id or source_id/field)
      sliceHint - Optional slice hint
      scaleHint - Per-dimension scale factors
      reductionMethod - Requested reduction method
      Returns:
      RandomAccessibleInterval containing the requested tensor
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String sourceId, String tensorId)
      Get a RandomAccessibleInterval for a tensor within a data source.
      Type Parameters:
      T - The pixel type
      Parameters:
      sourceId - Data source identifier
      tensorId - Tensor identifier within the source
      Returns:
      RandomAccessibleInterval containing the requested tensor
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String sourceId, String tensorId, SliceHint sliceHint)
      Get a RandomAccessibleInterval for a tensor with slice hint.
      Type Parameters:
      T - The pixel type
      Parameters:
      sourceId - Data source identifier
      tensorId - Tensor identifier within the source
      sliceHint - Optional slice hint
      Returns:
      RandomAccessibleInterval containing the requested tensor
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String sourceId, String tensorId, long[] scaleHint, String reductionMethod)
      Get a RandomAccessibleInterval for a tensor with scaled read options.
      Type Parameters:
      T - The pixel type
      Parameters:
      sourceId - Data source identifier
      tensorId - Tensor identifier within the source
      scaleHint - Per-dimension scale factors
      reductionMethod - Requested reduction method
      Returns:
      RandomAccessibleInterval containing the requested tensor
    • getTensor

      public <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> getTensor(String sourceId, String tensorId, SliceHint sliceHint, long[] scaleHint, String reductionMethod)
      Get a RandomAccessibleInterval for a tensor with all options.
      Type Parameters:
      T - The pixel type
      Parameters:
      sourceId - Data source identifier
      tensorId - Tensor identifier within the source
      sliceHint - Optional slice hint
      scaleHint - Per-dimension scale factors
      reductionMethod - Requested reduction method
      Returns:
      SerializableTensorImg containing the requested tensor (implements RandomAccessibleInterval)
    • getTensorAsPb

      public SerializedTensor getTensorAsPb(String sourceId, String tensorId, SliceHint sliceHint, long[] scaleHint, String reductionMethod)
      Get a SerializedTensor protobuf for cross-process transfer. Returns a protobuf containing connection info and chunk tickets for lazy reconstruction. The protobuf can be serialized to bytes and broadcast to worker processes (e.g., Spark), where each worker can call tensorFromPb() to reconstruct a lazy imglib2 array.
      Parameters:
      sourceId - Data source identifier
      tensorId - Tensor identifier within the source
      sliceHint - Optional slice hint
      scaleHint - Per-dimension scale factors
      reductionMethod - Requested reduction method
      Returns:
      SerializedTensor protobuf object
    • tensorFromPb

      public static <T extends net.imglib2.type.NativeType<T> & net.imglib2.type.numeric.RealType<T>> net.imglib2.RandomAccessibleInterval<T> tensorFromPb(SerializedTensor pb, long cacheBytes)
      Reconstruct a lazy RandomAccessibleInterval from SerializedTensor protobuf. Creates an imglib2 array that fetches chunks from the Flight server independently. Each worker process maintains its own connection pool and cache keyed by (location, authToken). If endpoints field is empty, calls GetFlightInfo on the server to rebuild the endpoint list.
      Type Parameters:
      T - The pixel type
      Parameters:
      pb - SerializedTensor protobuf object
      cacheBytes - Maximum cache size in bytes
      Returns:
      RandomAccessibleInterval with lazy chunk loading
    • close

      public void close()
      Specified by:
      close in interface AutoCloseable
    • healthCheck

      public Map<String,Object> healthCheck() throws IOException
      Check server health status via Flight action. Returns a map with health status information including: - status: "SERVING" or other status string - source_count: number of registered sources - metadata_db_enabled: whether metadata database is enabled - writable: whether server accepts uploads - uptime_seconds: server uptime in seconds
      Returns:
      Map containing health status
      Throws:
      IOException - If action fails
    • getUploadStatus

      public Map<String,Object> getUploadStatus(String sourceId) throws IOException
      Get upload status for a writable source.
      Parameters:
      sourceId - Source identifier returned by create_source()
      Returns:
      Map containing source_id, state, expected_chunks, and uploaded_chunks
      Throws:
      IOException - If the action fails
    • getUploadStatus

      public Map<String,Object> getUploadStatus(SerializedTensor pb) throws IOException
      Get upload status for a registration-first SerializedTensor handle. This helper is intended for cache-backed handles returned before upload completion, where tensor_descriptor.array_id is the source identifier.
      Parameters:
      pb - SerializedTensor handle from a registration-first flow
      Returns:
      Map containing source_id, state, expected_chunks, and uploaded_chunks
      Throws:
      IOException - If the action fails
    • waitForUploadReady

      public Map<String,Object> waitForUploadReady(String sourceId, long timeoutMillis, long pollIntervalMillis) throws IOException
      Poll upload status until the source reports READY.
      Parameters:
      sourceId - Source identifier returned by create_source()
      timeoutMillis - Maximum time to wait before timing out
      pollIntervalMillis - Delay between status checks
      Returns:
      Final upload status map when READY
      Throws:
      IOException - If the upload fails, times out, or the action fails
    • waitForUploadReady

      public Map<String,Object> waitForUploadReady(SerializedTensor pb, long timeoutMillis, long pollIntervalMillis) throws IOException
      Poll upload status until a registration-first SerializedTensor is READY.
      Parameters:
      pb - SerializedTensor handle from a registration-first flow
      timeoutMillis - Maximum time to wait before timing out
      pollIntervalMillis - Delay between status checks
      Returns:
      Final upload status map when READY
      Throws:
      IOException - If the upload fails, times out, or the action fails