FOBJ-SPI
FLAM Object Store Exit (FOBJ) Service Provider Interface (SPI) Version: 5.2.1-42969
FOBJ - Object Store Service Provider Interface

This service provider interface (SPI) allows customers to connect an arbitrary object store backend to the FLAM5 segment store layer at the object level. Cloud blob stores (S3, Azure Blob Storage, GCS), content-addressable stores, or any key/value store with string keys can be used as the physical archive medium. FLAM handles versioning, buffering, member management, and compression; the provider only needs to implement a small set of operations on a string-keyed object store.

The SPI is activated by the CLEP qualifier:

store.objuser(
    LIBRARY='libfsse',
    FUNC='FOBJUSR',
    PARAMETER='...',
    TRACE)

FLAM ships a reference implementation (libfsse / FOBJUSR) that wraps the built-in folder object store. The corresponding source file (FSSE.c) is an internal implementation and is not delivered as source to customers.

The customer-facing sample implementation is CSRC/SAMPLE/FOBJCLD.c. It demonstrates how to back the FOBJ SPI with an S3-compatible cloud object store (AWS S3, MinIO, Ceph, etc.) via libcurl and can be used as a coding template for custom providers.

Lifecycle

The provider handle and the storage connection are managed separately:

State: EMPTY (ppHdl == NULL)
  |
  | FOBJ_FUNC_NEW  -- allocate handle; store name + params
  v
State: NEW (handle allocated, storage not connected)
  |                        |
  | FOBJ_FUNC_OPN          | FOBJ_FUNC_DST / FOBJ_FUNC_EXS
  v                        | (stateless; provider self-manages connection)
State: OPEN                v
  |                    State: NEW
  | FOBJ_FUNC_GET/PUT/DEL/CHK
  |
  | FOBJ_FUNC_CLS  -- disconnect; handle stays in NEW state
  v
State: NEW
  |
  | FOBJ_FUNC_FRE  -- free handle; ppHdl = NULL
  v
State: EMPTY

FOBJ_FUNC_DST and FOBJ_FUNC_EXS are called in NEW state. The provider manages any temporary connection internally. FOBJ_FUNC_CLS closes the storage connection but does not free the handle. Every session must end with FOBJ_FUNC_FRE.

Object key format

Object keys are null-terminated strings generated by the FLAM5 SEGOBJ layer. The format is opaque to the provider; keys are guaranteed to be unique within a namespace/version combination and to consist of printable ASCII characters only (no slashes, spaces, or control characters).

Threading model

Each open handle is used by a single thread only. The provider does not need to implement internal locking per handle. Multiple handles to the same namespace may be active simultaneously; the provider is responsible for namespace-level concurrency control.

Interface standards

All function parameters are passed by reference (pointer). The function has no return value; the return code is the second parameter.

Parameter widths are fixed and architecture-independent:

  • 32-bit unsigned integer: unsigned int
  • 64-bit signed integer: long long
  • 64-bit unsigned integer: unsigned long long
  • Byte pointer: unsigned char*
  • String pointer: char*

Alignment rule: 32-bit fields that immediately precede a pointer must be paired so that together they fill one 64-bit slot, keeping the pointer on a 64-bit boundary. This prevents bus errors on strict-alignment architectures (SPARC, RISC-V, z/Architecture). When only one 32-bit field naturally precedes a pointer, a reserved dummy field is added as the second element of the pair (see e.g. TsFobjDel).

All strings passed to the provider are null-terminated; the matching length field contains the byte count without the null character.

Return code handling

The provider must set *piRetco to 0 for success or to a provider-defined non-zero value to signal an error. The provider must not use or depend on FLMRTC_* values from FLMRTC.h. The bridge layer (OBJSSE) translates any non-zero provider return code to the dedicated FLAM reason code FLMRTC_FOB and includes the provider RC and the message written to pcMsg in the FLAM error trace.

Exception: FOBJ_RTC_NFD is a reserved provider return code for FOBJ_FUNC_GET to indicate that the requested object does not exist. OBJSSE maps it to FLMRTC_NFD instead of FLMRTC_FOB so that the SEGOBJ layer can correctly distinguish "new store" from a genuine I/O error when reading the root object during open().

Coding example

The reference implementation FSSE.c wraps the built-in OBJFLDR folder object store and demonstrates the complete SPI lifecycle. The compiled provider is shipped as libfsse.