Skip to content

Add a Services API (service_mgr) for the native client: server version, backup and restore with streamed verbose output - #174

Open
mariuz wants to merge 2 commits into
fernandobatels:masterfrom
mariuz:services
Open

Add a Services API (service_mgr) for the native client: server version, backup and restore with streamed verbose output#174
mariuz wants to merge 2 commits into
fernandobatels:masterfrom
mariuz:services

Conversation

@mariuz

@mariuz mariuz commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

This implements the missing Services API for the native client — the gap we hit hardest while porting 43 Firebird architecture-paper samples to rsfbclient (context): the backup sample had to shell out to gbak, and the trace sample was the only twin across five language families that could not run its demonstration at all.

Per CONTRIBUTING this is API-sized, so treat the PR as a concrete proposal — happy to reshape the API, split it, or move parts behind discussion in an issue if you prefer that flow.

What it adds

rsfbclient-native

  • Activates the isc_service_attach / isc_service_start / isc_service_query / isc_service_detach bindings that were already present (commented out) in ibase.rs.
  • A new services module with NativeServiceManager<T: LinkageMarker>: a thin safe wrapper owning the service handle — per-linkage constructors (attach_dyn_link / attach_dyn_load), start/query/detach, detach-on-drop.

rsfbclient (behind the existing native_client feature)

  • services::ServiceManager with a small builder (host/port/user/pass, optional with_dyn_load(path); runtime dispatch between linkages like SimpleConnection, to avoid duplicating the connection builders' typestate).
  • server_version(), backup/restore with typed option structs (SvcBackupOptions: metadata_only, ignore_checksums, ignore_limbo, no_garbage_collect; SvcRestoreOptions: replace, page_size), and *_with_output variants that stream the verbose gbak log line by line while the action runs — the same isc_info_svc_line polling loop gbak -se uses.
  • SPB construction lives in two small documented helpers, because the Services API's classic trap is that the attach block uses one-byte lengths while start-request blocks use two-byte little-endian lengths.
  • Extensive rustdoc: a front-page "Services API" chapter plus full module docs, stressing that every action path is a server path, and why pure_rust cannot reach the service manager (its wire implementation doesn't carry the service opcodes).
  • examples/services.rs in the standard example shape.

Tests

src/tests/services.rs (native + remote only, plain feature-gated rather than mk_tests_default! since there is no per-backend matrix for services):

  • server_version returns a plausible version string.
  • backup_restore_roundtrip: creates a database with known rows, runs a verbose backup (asserting the log actually streams), restores under a new name, and verifies the rows in the restored copy, then drops it.
  • restore_without_replace_fails_on_existing: the isc_spb_res_create safety semantics.

Verification

  • All three new tests pass against Firebird 6.0 (LI-T6.0.0.2076, Linux aarch64, linking feature): test result: ok. 3 passed (services filter); the example streams the real gbak log (gbak:readied database ... gbak:creating file ...).
  • No regressions: the full cargo test -- --test-threads 1 shows the same five failures on this branch as on clean master against Firebird 6 (boolean ×2, execute_procedure, select_readcommited_with_nowait, server_engine — all pre-existing FB6 incompatibilities, unrelated to this change), with my three tests added to the passing set (85 → 88 passed).
  • cargo fmt --all -- --check passes; cargo build --examples clean.

Possible follow-ups (not in this PR to keep it reviewable)

The same NativeServiceManager primitive can carry the rest of the service family — trace sessions (isc_action_svc_trace_start/stop), nbackup, database properties (sweep interval, shutdown), user management, and validation/sweep — each is just another SPB layout over start + drain_output.

🤖 Generated with Claude Code

Implements the Firebird Services API - the administration channel that
gbak and the other command-line tools use - for the native client
(linking and dynamic_loading features).

rsfbclient-native:
  * activate the isc_service_attach/start/query/detach bindings that
    were already present (commented out) in ibase.rs
  * new services module: NativeServiceManager, a thin safe wrapper
    owning the service handle, with per-linkage constructors
    (attach_dyn_link / attach_dyn_load) and detach-on-drop

rsfbclient:
  * new services module (behind the native_client feature):
    ServiceManager + builder (host/port/user/pass, optional
    with_dyn_load), server_version(), backup/restore with typed
    option structs (SvcBackupOptions, SvcRestoreOptions), and
    _with_output variants that stream the verbose gbak log line by
    line while the action runs. SPB construction handles the
    version-2 attach block (one-byte lengths) and start-request
    blocks (two-byte lengths) - the classic Services API trap -
    in two small documented helpers.
  * front-page doc chapter and full rustdoc on the module, stressing
    that all action paths are SERVER paths
  * examples/services.rs: version query + verbose backup + restore

tests (src/tests/services.rs, native + remote only):
  * server_version returns a plausible version string
  * backup/restore round trip: known table content -> verbose backup
    (asserts the log actually streams) -> restore under a new name ->
    content verified in the restored copy
  * restore without replace over an existing database fails
    (isc_spb_res_create semantics)

All three tests pass against Firebird 6.0 (LI-T6.0.0.2076); the full
suite shows no regressions (the five failures present on master
against Firebird 6 - boolean/execute_procedure/nowait/server_engine -
are unchanged).
Comment thread rsfbclient-native/src/ibase.rs
The first version of this change added a second, live copy of
isc_service_attach/detach/query/start near the top of parse_functions!
while the original declarations stayed commented out further down.

Uncomment the existing ones instead, so the diff is only the removal of
the comment markers. parse_functions! maps each extern "C" block to a
trait method plus its linking/dyn_loading impls, so the position inside
the macro invocation makes no difference.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mariuz

mariuz commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

Verification after d7ed9cd (the in-place uncomment)

Re-ran everything on a clean toolchain (rustup stable 1.97.1, x86_64-unknown-linux-gnu) against Firebird 6 on localhost:3050LI-T6.0.0.2073 Firebird 6.0 3518df8.

Build / format

command result
cargo build --features "linking dynamic_loading" clean (only pre-existing warnings)
cargo build --features dynamic_loading --examples clean
cargo fmt --all -- --check clean

Testscargo test --features linking -- --test-threads 1

branch passed failed ignored
master 85 5 4
this PR (d7ed9cd) 88 5 4

Identical failure set on both, so no regressions — all five are pre-existing FB6 incompatibilities:

tests::params::linking::boolean
tests::row::linking::boolean
tests::row::linking::execute_procedure
tests::transaction::linking::select_readcommited_with_nowait
utils::linking::server_engine

The three added tests are the whole of the +3:

test tests::services::backup_restore_roundtrip ... ok
test tests::services::restore_without_replace_fails_on_existing ... ok
test tests::services::server_version ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 94 filtered out; finished in 1.54s

Examplecargo run --features linking --example services (after --example createdb), showing the log streaming while the backup runs:

server version: LI-T6.0.0.2073 Firebird 6.0 3518df8
backing up examples.fdb:
  gbak:readied database examples.fdb for backup
  gbak:creating file examples.fbk
  gbak:starting transaction
  gbak:use up to 1 parallel workers
  gbak:database examples.fdb has a page size of 8192 bytes.
  ...
restored examples.fbk -> examples_restored.fdb

Unrelated pre-existing issue spotted while doing this: cargo test --features dynamic_loading (without linking) does not compile — three E0283 "type annotations needed" errors at src/events.rs:126, from the two impl From<Connection<..>> for SimpleConnection candidates. It fails the same way on master, so it is not from this PR, but it does mean the dyn-load-only test configuration cannot run today. Happy to open a separate issue for it. The library and examples do build fine under that feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants