this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Avoid starting nodes that are already queued and improve return values

garrison eced367b f5051a1f

+66 -28
+62 -23
lib/trinity/scheduler.ex
··· 46 46 defstruct @enforce_keys 47 47 end 48 48 49 + defmodule NodeInfo do 50 + @type t :: %__MODULE__{ 51 + mfa: {module, atom, list}, 52 + status: :running | :stopped | :queued, 53 + } 54 + @enforce_keys [ 55 + :mfa, 56 + :status, 57 + ] 58 + defstruct @enforce_keys 59 + end 60 + 49 61 defmodule ProcInfo do 50 62 @type t :: %__MODULE__{ 51 63 trap_exit: boolean, ··· 74 86 @spec create_node(atom, {module, atom, list}) :: :ok 75 87 def create_node(node, {_m, _f, _a} = mfa) do 76 88 %{nodes: nodes} = get_sim() 89 + info = %NodeInfo{mfa: mfa, status: :stopped} 77 90 case :ets.lookup(nodes, node) do 78 - [] -> :ets.insert(nodes, {node, mfa}) 91 + [] -> :ets.insert(nodes, {node, info}) 79 92 [{_key, _existing}] -> raise ArgumentError, "Node #{inspect(node)} already exists" 80 93 end 81 94 :ok 82 95 end 83 96 84 - @spec start_node(atom, non_neg_integer) :: :ok 97 + @spec start_node(atom, non_neg_integer) :: :ok | {:error, :node_not_stopped | :node_not_found} 85 98 def start_node(node, delay) do 86 99 %{queue: queue, nodes: nodes, now: now} = get_sim() 87 - case :ets.member(nodes, node) do 88 - true -> :noop 89 - false -> raise ArgumentError, "Node #{inspect(node)} cannot be started because it does not exist" 100 + 101 + case :ets.lookup(nodes, node) do 102 + [{_key, %NodeInfo{status: :stopped} = info}] -> 103 + info = %{info | status: :queued} 104 + :ets.insert(nodes, {node, info}) 105 + 106 + enqueue_start_node(queue, now, node, delay) 107 + :ok 108 + 109 + [{_key, _info}] -> 110 + {:error, :node_not_stopped} 111 + 112 + [] -> 113 + {:error, :node_not_found} 90 114 end 91 - enqueue_start_node(queue, now, node, delay) 92 - :ok 93 115 end 94 116 95 117 @spec yield(non_neg_integer) :: :ok ··· 284 306 end 285 307 286 308 def handle_kill_node(node, from_pid) do 287 - %{node_procs: node_procs} = sim = get_sim() 288 - [{_node, pids}] = :ets.lookup(node_procs, node) 309 + %{nodes: nodes, node_procs: node_procs} = sim = get_sim() 310 + 311 + case :ets.lookup(nodes, node) do 312 + [{_node, %NodeInfo{status: :running} = info}] -> 313 + info = %{info | status: :stopped} 314 + :ets.insert(nodes, {node, info}) 315 + 316 + [{_node, pids}] = :ets.lookup(node_procs, node) 317 + # Killing a node from within the node is not currently allowed 318 + # TODO: maybe allow this? 319 + assert from_pid not in pids 289 320 290 - # Note: we can ignore links here because we currently only support links on the same node 291 - Enum.each(pids, fn pid -> 292 - # Killing a node from within the node is not currently allowed 293 - # TODO: maybe allow this? 294 - assert pid != from_pid 295 - destroy_process(sim, pid) 321 + # Note: we can ignore links here because we currently only support links on the same node 322 + Enum.each(pids, fn pid -> 323 + destroy_process(sim, pid) 324 + 325 + assert Process.alive?(pid) 326 + Process.exit(pid, :kill) 327 + 328 + receive do 329 + {:EXIT, ^pid, _reason} -> :noop 330 + end 331 + end) 332 + :ok 296 333 297 - assert Process.alive?(pid) 298 - Process.exit(pid, :kill) 334 + [{_node, %NodeInfo{}}] -> 335 + {:error, :node_not_running} 299 336 300 - receive do 301 - {:EXIT, ^pid, _reason} -> :noop 302 - end 303 - end) 337 + [] -> 338 + {:error, :node_not_found} 339 + end 304 340 end 305 341 306 342 defp destroy_or_message_linked(%Simulation{} = sim, for_pid, reason, visited) do ··· 414 450 supervisor_pid: supervisor_pid, 415 451 } = get_sim() 416 452 417 - [{_key, mfa}] = :ets.lookup(nodes, node) 418 - {m, f, a} = mfa 453 + [{_key, %NodeInfo{} = info}] = :ets.lookup(nodes, node) 454 + info = %{info | status: :running} 455 + :ets.insert(nodes, {node, info}) 456 + 457 + {m, f, a} = info.mfa 419 458 420 459 SimulationSupervisor.spawn_child(supervisor_pid, fn -> 421 460 put_proc_node(proc_nodes, node_procs, node)
+2 -2
lib/trinity/scheduler/simulation_supervisor.ex
··· 97 97 end 98 98 99 99 def handle_call({:kill_node, node, from_pid}, _from, %State{} = state) do 100 - Trinity.Scheduler.handle_kill_node(node, from_pid) 101 - {:reply, :ok, state} 100 + result = Trinity.Scheduler.handle_kill_node(node, from_pid) 101 + {:reply, result, state} 102 102 end 103 103 104 104 def handle_info({ref, result}, %State{} = state) when ref == state.ref do
+2 -3
lib/trinity/sim.ex
··· 26 26 Trinity.Scheduler.create_node(node, mfa) 27 27 end 28 28 29 - @spec start_node(atom, non_neg_integer) :: :ok 29 + @spec start_node(atom, non_neg_integer) :: :ok | {:error, :node_not_stopped | :node_not_found} 30 30 def start_node(node, delay \\ 0) do 31 31 Trinity.Scheduler.start_node(node, delay) 32 32 end 33 33 34 - @spec kill_node(atom) :: :ok 34 + @spec kill_node(atom) :: :ok | {:error, :node_not_running | :node_not_found} 35 35 def kill_node(node) do 36 36 %{supervisor_pid: supervisor_pid} = get_sim() 37 37 Trinity.Scheduler.SimulationSupervisor.kill_node(supervisor_pid, node) 38 - :ok 39 38 end 40 39 41 40 @spec simulated? :: boolean