Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions dag/gunbc/live_deploy/member_observe.dag
Original file line number Diff line number Diff line change
Expand Up @@ -158,21 +158,31 @@ fn entry_presence_in_parent(arm: ObservationArm, parent: String, name: String) -
}
}

type PresenceVia
= NoViaCause
| ViaCause { cause: String }

fn entry_presence(arm: ObservationArm, path: String) -> EntryPresence {
entry_presence_above(arm: arm, path: path, via: NoViaCause)
}

// Tail-recursive: `via` carries the cause of the nearest descendant whose parent could not be
// listed, which is the only cause a present ancestor can surface (absent and indeterminate
// ancestors pass through unchanged).
fn entry_presence_above(arm: ObservationArm, path: String, via: PresenceVia) -> EntryPresence {
let parent = path_parent(path: path)
let name = path_basename(path: path)
match entry_presence_in_parent(arm: arm, parent: parent, name: name) {
EntryPresent => EntryPresent
EntryPresent => match via {
NoViaCause => EntryPresent
ViaCause { cause: c } => EntryPresenceIndeterminate { cause: c }
}
EntryAbsent => EntryAbsent
EntryPresenceIndeterminate { cause } =>
if parent == "/" {
EntryPresenceIndeterminate { cause: cause }
} else {
match entry_presence(arm: arm, path: parent) {
EntryAbsent => EntryAbsent
EntryPresent => EntryPresenceIndeterminate { cause: cause }
EntryPresenceIndeterminate { cause: ancestor_cause } => EntryPresenceIndeterminate { cause: ancestor_cause }
}
entry_presence_above(arm: arm, path: parent, via: ViaCause { cause: cause })
}
}
}
Expand Down
36 changes: 26 additions & 10 deletions dag/gunbc/runner/runner_microvm_lifecycle_realize.dag
Original file line number Diff line number Diff line change
Expand Up @@ -190,19 +190,35 @@ fn cgroup_child_names(cgroup_path: NonEmptyStr) -> List<String>
}
}

// The walk is preorder over a pending list so the self-call is a tail call: the effectful reads
// (procs, child listing) happen once per node and the accumulator is carried, not concatenated
// from a non-tail recursive result.
type CgroupWalkPending { path: NonEmptyStr, depth: Int }

fn walk_cgroup(cgroup_path: NonEmptyStr, depth: Int) -> CgroupWalk
{
let here = CgroupWalkNode { path: cgroup_path, pids: cgroup_procs_pids(cgroup_path: cgroup_path) }
if depth <= 0 {
CgroupWalk { nodes: [here] }
walk_cgroup_pending(pending: [CgroupWalkPending { path: cgroup_path, depth: depth }], nodes: [])
}

fn walk_cgroup_pending(pending: List<CgroupWalkPending>, nodes: List<CgroupWalkNode>) -> CgroupWalk
{
match pending {
Empty => CgroupWalk { nodes: nodes }
Cons { head: item, tail: rest } =>
walk_cgroup_pending(
pending: concat(cgroup_walk_children(item: item), rest),
nodes: nodes |> list_push(CgroupWalkNode { path: item.path, pids: cgroup_procs_pids(cgroup_path: item.path) }),
)
}
}

fn cgroup_walk_children(item: CgroupWalkPending) -> List<CgroupWalkPending>
{
if item.depth <= 0 {
[]
} else {
fold(cgroup_child_names(cgroup_path: cgroup_path), init: CgroupWalk { nodes: [here] }, f: (acc, name) =>
CgroupWalk {
nodes: concat(
acc.nodes,
walk_cgroup(cgroup_path: cgroup_v2_child_path(parent: cgroup_path, child: trim(s: name) as NonEmptyStr), depth: depth - 1).nodes,
),
})
map(cgroup_child_names(cgroup_path: item.path), name =>
CgroupWalkPending { path: cgroup_v2_child_path(parent: item.path, child: trim(s: name) as NonEmptyStr), depth: item.depth - 1 })
}
}

Expand Down
Loading