v0.3.6-pre.009-fix.001
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-job-backfill-lib/src/runtime.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
/// Stable Job kind code used by the concrete historical RAW transaction Backfill runtime.
|
||||
pub const BACKFILL_JOB_KIND_CODE: &str = "solana.raw_transaction.backfill";
|
||||
@@ -26,7 +26,7 @@ pub enum BackfillJobPhase {
|
||||
Finished,
|
||||
}
|
||||
|
||||
impl BackfillJobPhase {
|
||||
impl crate::BackfillJobPhase {
|
||||
/// Returns the stable safe code for this concrete runtime phase.
|
||||
#[must_use]
|
||||
pub const fn code(self) -> &'static str {
|
||||
@@ -43,7 +43,7 @@ impl BackfillJobPhase {
|
||||
/// Complete safe latest-value snapshot of one concrete historical RAW transaction Backfill Job.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct BackfillJobSnapshot {
|
||||
phase: BackfillJobPhase,
|
||||
phase: crate::BackfillJobPhase,
|
||||
scope_kind: crate::BackfillScopeKind,
|
||||
discovery_boundary: std::option::Option<crate::BackfillDiscoveryBoundary>,
|
||||
candidates_selected: usize,
|
||||
@@ -64,10 +64,10 @@ pub struct BackfillJobSnapshot {
|
||||
failure_code: std::option::Option<ksp_core_lib::ErrorCode>,
|
||||
}
|
||||
|
||||
impl BackfillJobSnapshot {
|
||||
impl crate::BackfillJobSnapshot {
|
||||
fn initial(request: &crate::BackfillRequest) -> Self {
|
||||
return Self {
|
||||
phase: BackfillJobPhase::Created,
|
||||
phase: crate::BackfillJobPhase::Created,
|
||||
scope_kind: request.scope().kind(),
|
||||
discovery_boundary: std::option::Option::None,
|
||||
candidates_selected: 0,
|
||||
@@ -91,7 +91,7 @@ impl BackfillJobSnapshot {
|
||||
|
||||
/// Returns the concrete execution phase represented by this snapshot.
|
||||
#[must_use]
|
||||
pub const fn phase(&self) -> BackfillJobPhase {
|
||||
pub const fn phase(&self) -> crate::BackfillJobPhase {
|
||||
return self.phase;
|
||||
}
|
||||
|
||||
@@ -207,11 +207,11 @@ impl BackfillJobSnapshot {
|
||||
/// Cloneable runtime-neutral-facing latest-value source for concrete Backfill snapshots.
|
||||
#[derive(Clone)]
|
||||
pub struct BackfillSnapshotSource {
|
||||
receiver: tokio::sync::watch::Receiver<ksp_job_api::JobNotification<BackfillJobSnapshot>>,
|
||||
receiver: tokio::sync::watch::Receiver<ksp_job_api::JobNotification<crate::BackfillJobSnapshot>>,
|
||||
}
|
||||
|
||||
impl ksp_job_api::JobSnapshotSource for BackfillSnapshotSource {
|
||||
type Snapshot = BackfillJobSnapshot;
|
||||
impl ksp_job_api::JobSnapshotSource for crate::BackfillSnapshotSource {
|
||||
type Snapshot = crate::BackfillJobSnapshot;
|
||||
|
||||
fn current(&self) -> ksp_job_api::JobNotification<Self::Snapshot> {
|
||||
return self.receiver.borrow().clone();
|
||||
@@ -234,7 +234,7 @@ impl ksp_job_api::JobSnapshotSource for BackfillSnapshotSource {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BackfillSnapshotSource {
|
||||
impl std::fmt::Debug for crate::BackfillSnapshotSource {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let current = self.receiver.borrow();
|
||||
return formatter.debug_struct("BackfillSnapshotSource").field("sequence", ¤t.sequence()).field("state", ¤t.state()).finish();
|
||||
@@ -245,10 +245,10 @@ impl std::fmt::Debug for BackfillSnapshotSource {
|
||||
#[derive(Clone)]
|
||||
pub struct BackfillJobHandle {
|
||||
control: BackfillRuntimeControl,
|
||||
snapshots: BackfillSnapshotSource,
|
||||
snapshots: crate::BackfillSnapshotSource,
|
||||
}
|
||||
|
||||
impl BackfillJobHandle {
|
||||
impl crate::BackfillJobHandle {
|
||||
/// Requests cooperative cancellation and returns `true` only when accepted before terminal publication.
|
||||
#[must_use]
|
||||
pub fn cancel(&self) -> bool {
|
||||
@@ -257,7 +257,7 @@ impl BackfillJobHandle {
|
||||
|
||||
/// Returns an independent latest-value snapshot source for one listener.
|
||||
#[must_use]
|
||||
pub fn snapshots(&self) -> BackfillSnapshotSource {
|
||||
pub fn snapshots(&self) -> crate::BackfillSnapshotSource {
|
||||
return self.snapshots.clone();
|
||||
}
|
||||
|
||||
@@ -268,12 +268,12 @@ impl BackfillJobHandle {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BackfillJobHandle {
|
||||
impl std::fmt::Debug for crate::BackfillJobHandle {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter
|
||||
.debug_struct("BackfillJobHandle")
|
||||
.field("cancellation_requested", &self.is_cancellation_requested())
|
||||
.field("snapshot", &<BackfillSnapshotSource as ksp_job_api::JobSnapshotSource>::current(&self.snapshots))
|
||||
.field("snapshot", &<crate::BackfillSnapshotSource as ksp_job_api::JobSnapshotSource>::current(&self.snapshots))
|
||||
.finish();
|
||||
}
|
||||
}
|
||||
@@ -282,19 +282,19 @@ impl std::fmt::Debug for BackfillJobHandle {
|
||||
pub struct BackfillJobRuntime {
|
||||
request: crate::BackfillRequest,
|
||||
control: BackfillRuntimeControl,
|
||||
cancellation: BackfillCancellationSignal,
|
||||
publisher: BackfillRuntimePublisher,
|
||||
handle: BackfillJobHandle,
|
||||
cancellation: crate::BackfillCancellationSignal,
|
||||
publisher: crate::BackfillRuntimePublisher,
|
||||
handle: crate::BackfillJobHandle,
|
||||
}
|
||||
|
||||
impl BackfillJobRuntime {
|
||||
impl crate::BackfillJobRuntime {
|
||||
/// Creates one runtime in `Created` state and its stable latest-value channel.
|
||||
pub fn new(request: crate::BackfillRequest) -> ksp_core_lib::Result<Self> {
|
||||
let kind = match ksp_job_api::JobKindCode::new(BACKFILL_JOB_KIND_CODE) {
|
||||
let kind = match ksp_job_api::JobKindCode::new(crate::BACKFILL_JOB_KIND_CODE) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let initial_snapshot = BackfillJobSnapshot::initial(&request);
|
||||
let initial_snapshot = crate::BackfillJobSnapshot::initial(&request);
|
||||
let initial = ksp_job_api::JobNotification::new(
|
||||
request.job_id().clone(),
|
||||
kind.clone(),
|
||||
@@ -305,16 +305,16 @@ impl BackfillJobRuntime {
|
||||
let (snapshot_sender, snapshot_receiver) = tokio::sync::watch::channel(initial);
|
||||
let (cancel_sender, cancel_receiver) = tokio::sync::watch::channel(false);
|
||||
let control = BackfillRuntimeControl::new(cancel_sender);
|
||||
let cancellation = BackfillCancellationSignal::new(control.token(), cancel_receiver);
|
||||
let snapshots = BackfillSnapshotSource { receiver: snapshot_receiver };
|
||||
let handle = BackfillJobHandle { control: control.clone(), snapshots: snapshots.clone() };
|
||||
let publisher = BackfillRuntimePublisher { sender: snapshot_sender, id: request.job_id().clone(), kind };
|
||||
let cancellation = crate::BackfillCancellationSignal::new(control.token(), cancel_receiver);
|
||||
let snapshots = crate::BackfillSnapshotSource { receiver: snapshot_receiver };
|
||||
let handle = crate::BackfillJobHandle { control: control.clone(), snapshots: snapshots.clone() };
|
||||
let publisher = crate::BackfillRuntimePublisher { sender: snapshot_sender, id: request.job_id().clone(), kind };
|
||||
return std::result::Result::Ok(Self { request, control, cancellation, publisher, handle });
|
||||
}
|
||||
|
||||
/// Returns a cloneable control and latest-value observation handle before the runtime is moved into execution.
|
||||
#[must_use]
|
||||
pub fn handle(&self) -> BackfillJobHandle {
|
||||
pub fn handle(&self) -> crate::BackfillJobHandle {
|
||||
return self.handle.clone();
|
||||
}
|
||||
|
||||
@@ -323,7 +323,7 @@ impl BackfillJobRuntime {
|
||||
self,
|
||||
transport: &ksp_onchain_transport_lib::HttpTransportPool,
|
||||
store: &ksp_store_lib::Store,
|
||||
) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
if self.cancellation.is_requested() {
|
||||
let claimed = self.control.claim_normal_terminal();
|
||||
if claimed != TerminalClaim::Cancelled {
|
||||
@@ -331,7 +331,7 @@ impl BackfillJobRuntime {
|
||||
}
|
||||
return self.publisher.publish_cancelled_from_created();
|
||||
}
|
||||
let started = self.publisher.publish_running(BackfillJobPhase::Discovering);
|
||||
let started = self.publisher.publish_running(crate::BackfillJobPhase::Discovering);
|
||||
if let std::result::Result::Err(error) = started {
|
||||
self.control.claim_failed();
|
||||
return std::result::Result::Err(error);
|
||||
@@ -393,7 +393,7 @@ impl BackfillJobRuntime {
|
||||
};
|
||||
}
|
||||
|
||||
fn finish_cancelled(&self) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
fn finish_cancelled(&self) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
let terminal = self.control.claim_normal_terminal();
|
||||
if terminal != TerminalClaim::Cancelled {
|
||||
return std::result::Result::Err(runtime_error("terminal.cancelled"));
|
||||
@@ -408,7 +408,7 @@ impl BackfillJobRuntime {
|
||||
|
||||
/// Internal atomic terminal/cancellation arbitration shared by runtime and external handle.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct BackfillRuntimeControl {
|
||||
struct BackfillRuntimeControl {
|
||||
state: std::sync::Arc<std::sync::atomic::AtomicU8>,
|
||||
token: ksp_job_api::JobCancellationToken,
|
||||
cancel_sender: tokio::sync::watch::Sender<bool>,
|
||||
@@ -416,7 +416,7 @@ pub(crate) struct BackfillRuntimeControl {
|
||||
|
||||
impl BackfillRuntimeControl {
|
||||
/// Creates one active control state paired with the cancellation wake channel.
|
||||
pub(crate) fn new(cancel_sender: tokio::sync::watch::Sender<bool>) -> Self {
|
||||
fn new(cancel_sender: tokio::sync::watch::Sender<bool>) -> Self {
|
||||
return Self {
|
||||
state: std::sync::Arc::new(std::sync::atomic::AtomicU8::new(CONTROL_ACTIVE)),
|
||||
token: ksp_job_api::JobCancellationToken::new(),
|
||||
@@ -425,12 +425,12 @@ impl BackfillRuntimeControl {
|
||||
}
|
||||
|
||||
/// Returns the runtime-neutral cancellation token mirrored by this control.
|
||||
pub(crate) fn token(&self) -> ksp_job_api::JobCancellationToken {
|
||||
fn token(&self) -> ksp_job_api::JobCancellationToken {
|
||||
return self.token.clone();
|
||||
}
|
||||
|
||||
/// Atomically accepts the first pre-terminal cancellation request.
|
||||
pub(crate) fn request_cancellation(&self) -> bool {
|
||||
fn request_cancellation(&self) -> bool {
|
||||
let accepted = self
|
||||
.state
|
||||
.compare_exchange(CONTROL_ACTIVE, CONTROL_CANCELLATION_REQUESTED, std::sync::atomic::Ordering::AcqRel, std::sync::atomic::Ordering::Acquire)
|
||||
@@ -442,12 +442,12 @@ impl BackfillRuntimeControl {
|
||||
}
|
||||
|
||||
/// Returns whether cooperative cancellation was accepted.
|
||||
pub(crate) fn is_cancellation_requested(&self) -> bool {
|
||||
fn is_cancellation_requested(&self) -> bool {
|
||||
return self.token.is_cancellation_requested();
|
||||
}
|
||||
|
||||
/// Atomically resolves the completion-versus-cancellation terminal race.
|
||||
pub(crate) fn claim_normal_terminal(&self) -> TerminalClaim {
|
||||
fn claim_normal_terminal(&self) -> TerminalClaim {
|
||||
let completed =
|
||||
self.state.compare_exchange(CONTROL_ACTIVE, CONTROL_COMPLETED, std::sync::atomic::Ordering::AcqRel, std::sync::atomic::Ordering::Acquire);
|
||||
if completed.is_ok() {
|
||||
@@ -466,7 +466,7 @@ impl BackfillRuntimeControl {
|
||||
}
|
||||
|
||||
/// Marks a non-terminal control as failed, overriding a pending cancellation request.
|
||||
pub(crate) fn claim_failed(&self) {
|
||||
fn claim_failed(&self) {
|
||||
loop {
|
||||
let state = self.state.load(std::sync::atomic::Ordering::Acquire);
|
||||
if matches!(state, CONTROL_COMPLETED | CONTROL_CANCELLED | CONTROL_FAILED) {
|
||||
@@ -487,7 +487,7 @@ pub(crate) struct BackfillCancellationSignal {
|
||||
receiver: tokio::sync::watch::Receiver<bool>,
|
||||
}
|
||||
|
||||
impl BackfillCancellationSignal {
|
||||
impl crate::BackfillCancellationSignal {
|
||||
/// Creates one signal from the runtime-neutral token and Tokio wake receiver.
|
||||
pub(crate) fn new(token: ksp_job_api::JobCancellationToken, receiver: tokio::sync::watch::Receiver<bool>) -> Self {
|
||||
return Self { token, receiver };
|
||||
@@ -529,7 +529,7 @@ async fn wait_for_cancellation(token: &ksp_job_api::JobCancellationToken, receiv
|
||||
|
||||
/// Internal result of atomically claiming a normal terminal state.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum TerminalClaim {
|
||||
enum TerminalClaim {
|
||||
Completed,
|
||||
Cancelled,
|
||||
Failed,
|
||||
@@ -538,23 +538,23 @@ pub(crate) enum TerminalClaim {
|
||||
/// Internal latest-value publisher owning the concrete Backfill notification stream.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct BackfillRuntimePublisher {
|
||||
sender: tokio::sync::watch::Sender<ksp_job_api::JobNotification<BackfillJobSnapshot>>,
|
||||
sender: tokio::sync::watch::Sender<ksp_job_api::JobNotification<crate::BackfillJobSnapshot>>,
|
||||
id: ksp_job_api::JobId,
|
||||
kind: ksp_job_api::JobKindCode,
|
||||
}
|
||||
|
||||
impl BackfillRuntimePublisher {
|
||||
impl crate::BackfillRuntimePublisher {
|
||||
/// Publishes one non-terminal running phase.
|
||||
pub(crate) fn publish_running(&self, phase: BackfillJobPhase) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
pub(crate) fn publish_running(&self, phase: crate::BackfillJobPhase) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_with(ksp_job_api::JobState::Running, |snapshot| {
|
||||
snapshot.phase = phase;
|
||||
});
|
||||
}
|
||||
|
||||
/// Publishes the complete bounded discovery result as the current execution snapshot.
|
||||
pub(crate) fn publish_discovery(&self, discovery: &crate::BackfillDiscovery) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
pub(crate) fn publish_discovery(&self, discovery: &crate::BackfillDiscovery) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_with(ksp_job_api::JobState::Running, |snapshot| {
|
||||
snapshot.phase = BackfillJobPhase::Executing;
|
||||
snapshot.phase = crate::BackfillJobPhase::Executing;
|
||||
snapshot.discovery_boundary = std::option::Option::Some(discovery.boundary());
|
||||
snapshot.candidates_selected = discovery.candidates().len();
|
||||
});
|
||||
@@ -566,25 +566,25 @@ impl BackfillRuntimePublisher {
|
||||
progress: &crate::BackfillExecutionProgress,
|
||||
cancelling: bool,
|
||||
draining: bool,
|
||||
) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
let state = if cancelling { ksp_job_api::JobState::Cancelling } else { ksp_job_api::JobState::Running };
|
||||
return self.publish_with(state, |snapshot| {
|
||||
snapshot.phase = if draining { BackfillJobPhase::Draining } else { BackfillJobPhase::Executing };
|
||||
snapshot.phase = if draining { crate::BackfillJobPhase::Draining } else { crate::BackfillJobPhase::Executing };
|
||||
apply_progress(snapshot, progress);
|
||||
});
|
||||
}
|
||||
|
||||
/// Publishes cancellation observation before terminal cancellation.
|
||||
pub(crate) fn publish_cancelling(&self) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
pub(crate) fn publish_cancelling(&self) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_with(ksp_job_api::JobState::Cancelling, |snapshot| {
|
||||
snapshot.phase = BackfillJobPhase::Draining;
|
||||
snapshot.phase = crate::BackfillJobPhase::Draining;
|
||||
});
|
||||
}
|
||||
|
||||
/// Publishes the drained batch state while cancellation is terminalizing.
|
||||
pub(crate) fn publish_batch_cancelling(&self, batch: &crate::BackfillExecutionBatch) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
pub(crate) fn publish_batch_cancelling(&self, batch: &crate::BackfillExecutionBatch) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_with(ksp_job_api::JobState::Cancelling, |snapshot| {
|
||||
snapshot.phase = BackfillJobPhase::Draining;
|
||||
snapshot.phase = crate::BackfillJobPhase::Draining;
|
||||
apply_batch(snapshot, batch);
|
||||
});
|
||||
}
|
||||
@@ -595,16 +595,16 @@ impl BackfillRuntimePublisher {
|
||||
batch: &crate::BackfillExecutionBatch,
|
||||
state: ksp_job_api::JobState,
|
||||
failure_code: std::option::Option<ksp_core_lib::ErrorCode>,
|
||||
) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_with(state, |snapshot| {
|
||||
snapshot.phase = BackfillJobPhase::Finished;
|
||||
snapshot.phase = crate::BackfillJobPhase::Finished;
|
||||
snapshot.failure_code = failure_code;
|
||||
apply_batch(snapshot, batch);
|
||||
});
|
||||
}
|
||||
|
||||
/// Publishes a terminal failure before a batch exists.
|
||||
pub(crate) fn publish_failed(&self, code: ksp_core_lib::ErrorCode) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
pub(crate) fn publish_failed(&self, code: ksp_core_lib::ErrorCode) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_terminal(ksp_job_api::JobState::Failed, std::option::Option::Some(code));
|
||||
}
|
||||
|
||||
@@ -613,23 +613,23 @@ impl BackfillRuntimePublisher {
|
||||
&self,
|
||||
state: ksp_job_api::JobState,
|
||||
failure_code: std::option::Option<ksp_core_lib::ErrorCode>,
|
||||
) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_with(state, |snapshot| {
|
||||
snapshot.phase = BackfillJobPhase::Finished;
|
||||
snapshot.phase = crate::BackfillJobPhase::Finished;
|
||||
snapshot.failure_code = failure_code;
|
||||
});
|
||||
}
|
||||
|
||||
/// Publishes direct Created-to-Cancelled termination before execution starts.
|
||||
pub(crate) fn publish_cancelled_from_created(&self) -> ksp_core_lib::Result<BackfillJobSnapshot> {
|
||||
pub(crate) fn publish_cancelled_from_created(&self) -> ksp_core_lib::Result<crate::BackfillJobSnapshot> {
|
||||
return self.publish_with(ksp_job_api::JobState::Cancelled, |snapshot| {
|
||||
snapshot.phase = BackfillJobPhase::Finished;
|
||||
snapshot.phase = crate::BackfillJobPhase::Finished;
|
||||
});
|
||||
}
|
||||
|
||||
fn publish_with<F>(&self, state: ksp_job_api::JobState, update: F) -> ksp_core_lib::Result<BackfillJobSnapshot>
|
||||
fn publish_with<F>(&self, state: ksp_job_api::JobState, update: F) -> ksp_core_lib::Result<crate::BackfillJobSnapshot>
|
||||
where
|
||||
F: FnOnce(&mut BackfillJobSnapshot),
|
||||
F: FnOnce(&mut crate::BackfillJobSnapshot),
|
||||
{
|
||||
let current = self.sender.borrow().clone();
|
||||
if current.state().is_terminal() {
|
||||
@@ -668,7 +668,7 @@ fn valid_snapshot_transition(source: ksp_job_api::JobState, target: ksp_job_api:
|
||||
);
|
||||
}
|
||||
|
||||
fn apply_progress(snapshot: &mut BackfillJobSnapshot, progress: &crate::BackfillExecutionProgress) {
|
||||
fn apply_progress(snapshot: &mut crate::BackfillJobSnapshot, progress: &crate::BackfillExecutionProgress) {
|
||||
snapshot.candidates_admitted = progress.admitted_count();
|
||||
snapshot.candidates_finished = progress.finished_count();
|
||||
snapshot.entities_inserted = progress.inserted_count();
|
||||
@@ -685,7 +685,7 @@ fn apply_progress(snapshot: &mut BackfillJobSnapshot, progress: &crate::Backfill
|
||||
snapshot.checkpoint = std::option::Option::Some(progress.checkpoint().clone());
|
||||
}
|
||||
|
||||
fn apply_batch(snapshot: &mut BackfillJobSnapshot, batch: &crate::BackfillExecutionBatch) {
|
||||
fn apply_batch(snapshot: &mut crate::BackfillJobSnapshot, batch: &crate::BackfillExecutionBatch) {
|
||||
snapshot.candidates_admitted = batch.admitted_count();
|
||||
snapshot.candidates_finished = batch.finished_count();
|
||||
snapshot.entities_inserted = batch.inserted_count();
|
||||
|
||||
Reference in New Issue
Block a user