Skip to content

add BFT enforcement for bulk storage objects - #6438

Open
isegall-da wants to merge 18 commits into
mainfrom
isegall/bulk-bft
Open

add BFT enforcement for bulk storage objects#6438
isegall-da wants to merge 18 commits into
mainfrom
isegall/bulk-bft

Conversation

@isegall-da

@isegall-da isegall-da commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #6495

Pull Request Checklist

Cluster Testing

  • If a cluster test is required, comment /cluster_test on this PR to request it, and ping someone with access to the DA-internal system to approve it.
  • If an upgrade test is required, comment /upgrade_test on this PR to request it, and ping someone with access to the DA-internal system to approve it.
  • If a hard-migration test is required (from the latest release), comment /hdm_test on this PR to request it, and ping someone with access to the DA-internal system to approve it.
  • If a logical synchronizer upgrade test is required (from canton-3.5), comment /lsu_test on this PR to request it, and ping someone with access to the DA-internal system to approve it.

PR Guidelines

  • Include any change that might be observable by our partners or affect their deployment in the release notes.
  • Specify fixed issues with Fixes #n, and mention issues worked on using #n
  • Include a screenshot for frontend-related PRs - see README or use your favorite screenshot tool

Merge Guidelines

  • Make the git commit message look sensible when squash-merging on GitHub (most likely: just copy your PR description).

Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
NotUsed,
] = {
Flow[(T, Seq[ObjectKeyAndChecksum])].mapAsync(parallelism = 1) { case (t, obj) =>
Flow[(T, Seq[ObjectKeyAndChecksum])].flatMapConcat { case (t, obj) =>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was leaking pipelines, it created a new one that did not get destroyed when the main one was.

@isegall-da
isegall-da marked this pull request as ready for review July 21, 2026 20:22
@isegall-da isegall-da changed the title WIP: add BFT enforcement for bulk storage objects add BFT enforcement for bulk storage objects Jul 21, 2026
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
Signed-off-by: Itai Segall <itai.segall@digitalasset.com>
x-jvm-package: scan
operationId: "getBulkObjectChecksums"
description: |
**Under Development, do not use in production yet** Get checksums for bulk history objects. Uses both staging and committed objects.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**Under Development, do not use in production yet** Get checksums for bulk history objects. Uses both staging and committed objects.
**Under Development, do not use in production yet** Get checksums for bulk history objects. Searches for object_keys in both staging and committed objects.

Minor suggestion

}
}

protected def closeScanConnection(): Option[SyncCloseable] =

@ray-roestenburg-da ray-roestenburg-da Jul 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't really close, it creates a SyncCloseable (could be confusing)

httpClient: HttpClient,
templateJsonDecoder: TemplateJsonDecoder,
): Future[BftScanConnection] =
blocking {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the mutex.exclusive looks like a special mutex to especially not having to use blocking:

 Lock to be used instead of blocking synchronized

so I think the blocking should be removed.


import scala.concurrent.{ExecutionContextExecutor, Future, blocking}

trait HasPeerBftScanConnection {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd make this a class that owns one connection instead of a trait.

As a trait, the connection state is mixed invisibly into the host class, and the dependencies are method parameters, but only the first caller's arguments are ever used, so a second call site passing a different store or config silently gets the wrong connection.

The mixer also has to remember to wire closeScanConnection() into its closing sequence.

Suggestion:

  class PeerBftScanConnection(store: ScanStore, svName: String, ...) extends AutoCloseable {
    @volatile private var started = false
    lazy val connection: Future[BftScanConnection] = {
      started = true
      BftScanConnection.peerScanConnection(...)
    }
    override def close(): Unit = if (started) connection.foreach(_.close())
  }

Constructor params pin the dependencies, lazy val gives thread-safe create-once semantics (no mutex, no var, no blocking), caching the future avoids creating two connections on concurrent first calls, and whoever constructs it closes it. Both return a closed connection after close(). But here that's a local owner bug (use-after-close), not a silent failure when calling getOrCreateScanConnection.

If we ever want this fully airtight (post-close access fails loudly with AbortedDueToShutdown, and close() waits for an in-flight creation instead of racing it), extending FlagCloseable and wrapping the accessor in synchronizeWithClosingF fixes that. For a connection closed once at node shutdown I don't think we need that here though.

@ray-roestenburg-da ray-roestenburg-da left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, please have a look at my comments re: HasPeerBftScanConnection

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.

Add BFT checks as a condition for moving objects from staging to committed in bulk storage

2 participants