Coverage Report

Created: 2026-07-21 15:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/build/source/nativelink-util/src/operation_state_manager.rs
Line
Count
Source
1
// Copyright 2024 The NativeLink Authors. All rights reserved.
2
//
3
// Licensed under the Functional Source License, Version 1.1, Apache 2.0 Future License (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//    See LICENSE file for details
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
use core::pin::Pin;
16
use std::sync::Arc;
17
use std::time::SystemTime;
18
19
use async_trait::async_trait;
20
use bitflags::bitflags;
21
use futures::Stream;
22
use nativelink_error::Error;
23
use nativelink_metric::MetricsComponent;
24
25
use crate::action_messages::{
26
    ActionInfo, ActionStage, ActionState, ActionUniqueKey, OperationId, WorkerId,
27
};
28
use crate::common::DigestInfo;
29
use crate::origin_event::OriginMetadata;
30
31
bitflags! {
32
    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33
    pub struct OperationStageFlags: u32 {
34
        const CacheCheck = 1 << 1;
35
        const Queued     = 1 << 2;
36
        const Executing  = 1 << 3;
37
        const Completed  = 1 << 4;
38
        const Any        = u32::MAX;
39
    }
40
}
41
42
impl Default for OperationStageFlags {
43
646
    fn default() -> Self {
44
646
        Self::Any
45
646
    }
46
}
47
48
#[async_trait]
49
pub trait ActionStateResult: Send + Sync + 'static {
50
    /// Provides the current state of the action.
51
    async fn as_state(&self) -> Result<(Arc<ActionState>, Option<OriginMetadata>), Error>;
52
    /// Waits for the state of the action to change.
53
    async fn changed(&mut self) -> Result<(Arc<ActionState>, Option<OriginMetadata>), Error>;
54
    /// Provide result as action info. This behavior will not be supported by all implementations.
55
    async fn as_action_info(&self) -> Result<(Arc<ActionInfo>, Option<OriginMetadata>), Error>;
56
}
57
58
/// The direction in which the results are ordered.
59
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60
pub enum OrderDirection {
61
    Asc,
62
    Desc,
63
}
64
65
/// The filters used to query operations from the state manager.
66
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)]
67
pub struct OperationFilter {
68
    // TODO(palfrey): create rust builder pattern?
69
    /// The stage(s) that the operation must be in.
70
    pub stages: OperationStageFlags,
71
72
    /// The client operation id.
73
    pub client_operation_id: Option<OperationId>,
74
75
    /// The operation id.
76
    pub operation_id: Option<OperationId>,
77
78
    /// The worker that the operation must be assigned to.
79
    pub worker_id: Option<WorkerId>,
80
81
    /// The digest of the action that the operation must have.
82
    pub action_digest: Option<DigestInfo>,
83
84
    /// The operation must have its worker timestamp before this time.
85
    pub worker_update_before: Option<SystemTime>,
86
87
    /// The operation must have been completed before this time.
88
    pub completed_before: Option<SystemTime>,
89
90
    /// The unique key for filtering specific action results.
91
    pub unique_key: Option<ActionUniqueKey>,
92
93
    /// If the results should be ordered by priority and in which direction.
94
    pub order_by_priority_direction: Option<OrderDirection>,
95
}
96
97
pub type ActionStateResultStream<'a> =
98
    Pin<Box<dyn Stream<Item = Box<dyn ActionStateResult>> + Send + 'a>>;
99
100
#[async_trait]
101
pub trait ClientStateManager: Sync + Send + Unpin + MetricsComponent + 'static {
102
    /// Add a new action to the queue or joins an existing action.
103
    async fn add_action(
104
        &self,
105
        client_operation_id: OperationId,
106
        action_info: Arc<ActionInfo>,
107
    ) -> Result<Box<dyn ActionStateResult>, Error>;
108
109
    /// Returns a stream of operations that match the filter.
110
    async fn filter_operations(
111
        &self,
112
        filter: OperationFilter,
113
    ) -> Result<ActionStateResultStream, Error>;
114
}
115
116
/// The type of update to perform on an operation.
117
#[derive(Debug, PartialEq, Clone)]
118
#[allow(
119
    clippy::large_enum_variant,
120
    reason = "TODO Fix this. Breaks on stable, but not on nightly"
121
)]
122
pub enum UpdateOperationType {
123
    /// Notification that the operation is still alive.
124
    KeepAlive,
125
126
    /// Notification that the operation has been updated.
127
    UpdateWithActionStage(ActionStage),
128
129
    /// Notification that the operation has been completed.
130
    UpdateWithError(Error),
131
132
    /// Notification that the worker disconnected.
133
    UpdateWithDisconnect,
134
135
    /// Notification that the execution stage has completed and it's just IO happening now.
136
    ExecutionComplete,
137
}
138
139
#[async_trait]
140
pub trait WorkerStateManager: Sync + Send + MetricsComponent {
141
    /// Update that state of an operation.
142
    /// The worker must also send periodic updates even if the state
143
    /// did not change with a modified timestamp in order to prevent
144
    /// the operation from being considered stale and being rescheduled.
145
    async fn update_operation(
146
        &self,
147
        operation_id: &OperationId,
148
        worker_id: &WorkerId,
149
        update: UpdateOperationType,
150
    ) -> Result<(), Error>;
151
}
152
153
#[async_trait]
154
pub trait MatchingEngineStateManager: Sync + Send + MetricsComponent {
155
    /// Returns a stream of operations that match the filter.
156
    async fn filter_operations<'a>(
157
        &'a self,
158
        filter: OperationFilter,
159
    ) -> Result<ActionStateResultStream<'a>, Error>;
160
161
    /// Assign an operation to a worker or unassign it.
162
    async fn assign_operation(
163
        &self,
164
        operation_id: &OperationId,
165
        worker_id_or_reason_for_unassign: Result<&WorkerId, Error>,
166
    ) -> Result<(), Error>;
167
}