Skip to content

Expose the Firebird 5 parallel workers and in-place ODS upgrade service options - #23

Open
mariuz wants to merge 4 commits into
MWASoftware:mainfrom
mariuz:add-parallel-workers
Open

Expose the Firebird 5 parallel workers and in-place ODS upgrade service options#23
mariuz wants to merge 4 commits into
MWASoftware:mainfrom
mariuz:add-parallel-workers

Conversation

@mariuz

@mariuz mariuz commented Jul 26, 2026

Copy link
Copy Markdown

Firebird 5 can run a backup or restore with several workers, as gbak -par
does, but there is currently no way to ask for it: TIBXBackupService and
TIBXRestoreService build their service parameter block without it.

Change

A published ParallelWorkers property on TIBXBackupRestoreService, the base
both services share. isc_spb_bkp_parallel_workers and
isc_spb_res_parallel_workers are the same parameter code, so one property
serves both directions.

The parameter is only added when it is greater than one and the server is
Firebird 5 or later, so nothing changes for existing callers, and an older
server — which rejects the parameter — never sees it. Zero or one means the
present single-threaded behaviour, which is also the default.

Depends on

MWASoftware/fbintf#8, which adds the isc_spb_bkp_parallel_workers constant.
client/include/consts_pub.inc predates Firebird 5 and does not define it, so
this will not compile without that change.

Verified

Against a live Firebird 6.0.0 server, through TIBXClientSideBackupService:

  • ParallelWorkers = 1 — the parameter is not sent, backup behaves as before
  • ParallelWorkers = 4isc_spb_bkp_parallel_workers = 4 is sent (checked
    with a temporary trace at the point it is added), the server accepts it, and
    the resulting file restores to a working database with all its objects

Found while adding Firebird 4/5/6 support to Marathon, where the option is now
offered on its Database Maintenance dialog.

mariuz added 2 commits July 26, 2026 21:33
Firebird 5 can run a backup or restore with several workers, as
gbak -par does, but there was no way to ask for it: TIBXBackupService
and TIBXRestoreService build their service parameter block without it.

Adds a published ParallelWorkers property to TIBXBackupRestoreService,
the base both share - isc_spb_bkp_parallel_workers and
isc_spb_res_parallel_workers are the same parameter code, so one
property serves both directions.

The parameter is only sent when it is greater than one and the server is
Firebird 5 or later, so nothing changes for existing callers or older
servers, which reject the parameter. Zero or one means the default
single-threaded behaviour.

Requires the isc_spb_bkp_parallel_workers constant, which fbintf does
not currently define: MWASoftware/fbintf#8.

Verified against a live Firebird 6.0.0 server: with one worker the
parameter is not sent; with four it is, the server accepts it, and the
resulting backup restores to a working database.
Firebird 5 can upgrade a database's on-disk structure in place, as
gfix -upgrade does, instead of requiring a backup and restore. There was
no way to ask for it: TIBXValidationService maps its options onto the
isc_spb_rpr_* bits and had no entry for it.

Adds UpgradeODS to TValidateOption, appended rather than inserted so the
existing values keep their ordinals, and sends isc_spb_rpr_upgrade_db
only when the server is Firebird 5 or later - an older one rejects the
option.

Requires the isc_spb_rpr_upgrade_db constant, which fbintf does not
currently define.

Verified against a live Firebird 6.0.0 server: the assembled repair
parameter is 0x1000 and the request completes, leaving a database
already at the server's format unchanged.
@mariuz mariuz changed the title Allow a backup or restore to request Firebird 5 parallel workers Expose the Firebird 5 parallel workers and in-place ODS upgrade service options Jul 26, 2026
mariuz added 2 commits July 26, 2026 22:39
isc_dpb_page_size is an integer DPB parameter, but GenerateDPB grouped it
with the string ones and wrote it with SetAsString. That stores the digits
as text, and the clumplet writer rejects an integer parameter carrying more
than four bytes, so

  DB.Params.Values['page_size'] := '16384';
  DB.CreateDatabase;

fails with

  Invalid clumplet buffer structure: length of integer exceeds 4 bytes (5)

Only the four-digit page sizes appeared to work, and those worked by
accident: TFBAttachment.GenerateCreateDatabaseSQL reads the item back with
AsString and pastes it into PAGE_SIZE, so the text happened to round-trip.
Setting it as an integer fixes the five-digit sizes and leaves the create
path unchanged, since getAsString on an integer item returns IntToStr of
its value.

Verified against Firebird 6.0.0: creating a database with page_size 16384
now yields MON$DATABASE.MON$PAGE_SIZE = 16384.
TIBTransaction.Create added itself to FTransactionList without checking
it was still there, while Destroy already guarded the matching Remove.
That asymmetry is an access violation on the way out of a GUI program:

  EAccessViolation
    CREATE, line 1603 of runtime/nongui/IBDatabase.pas
    ...
    FREECOMPONENT / PROCESSASYNCCALLQUEUE
    DESTROY, line 137 of include/application.inc
    INTERFACES_$$_finalize$, line 38 of interfaces.pas

The LCL frees forms left on Application's async release queue from
inside Application.Destroy, which runs from interfaces.pas finalization
- by which time this unit may already have finalized. Tearing down a
data-aware control there reaches IBX again and constructs a transaction,
and the list it wants to join has gone.

The guard Destroy already had did not work either. Finalization called
Free without nilling, so Assigned stayed true on a dangling pointer and
the test let the code through to read released memory. FreeAndNil is
what makes both guards mean anything.

Left alone deliberately: FCriticalSection.Enter/Leave around
EndTransaction have the same exposure, but pairing a lock with a nil
check is a change to the locking rather than a missing guard, and
nothing has been seen to hit it.

Found from a symbolic backtrace out of Marathon, whose only symptom was
an exit code of 217 after the window had closed and the work was saved.
Verified by reasoning and by a full pass of that project's suites; the
crash itself is intermittent and needs a real window close, so it has
not been watched to disappear.
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.

1 participant