diff --git a/src/plotman/_tests/manager_test.py b/src/plotman/_tests/manager_test.py index 2f425955..a06965dc 100755 --- a/src/plotman/_tests/manager_test.py +++ b/src/plotman/_tests/manager_test.py @@ -14,7 +14,8 @@ def sched_cfg(): polling_time_s=2, tmpdir_stagger_phase_major=3, tmpdir_stagger_phase_minor=0, - tmpdir_max_jobs=3 + tmpdir_max_jobs=3, + stop_when_dst_full=False ) @pytest.fixture diff --git a/src/plotman/archive.py b/src/plotman/archive.py index bfd757ee..2f861d1f 100644 --- a/src/plotman/archive.py +++ b/src/plotman/archive.py @@ -158,8 +158,7 @@ def archive(dir_cfg, all_jobs): return(False, 'No free archive dirs found.') archdir = '' - available = [(d, space) for (d, space) in archdir_freebytes.items() if - space > 1.2 * plot_util.get_k32_plotsize()] + available = [(d, space) for (d, space) in archdir_freebytes.items() if plot_util.enough_space_for_k32(space)] if len(available) > 0: index = min(dir_cfg.archive.index, len(available) - 1) (archdir, freespace) = sorted(available)[index] diff --git a/src/plotman/configuration.py b/src/plotman/configuration.py index 9e92ea5e..9a9e9daa 100644 --- a/src/plotman/configuration.py +++ b/src/plotman/configuration.py @@ -69,6 +69,7 @@ class Scheduling: tmpdir_stagger_phase_major: int tmpdir_stagger_phase_minor: int tmpdir_stagger_phase_limit: int = 1 # If not explicit, "tmpdir_stagger_phase_limit" will default to 1 + stop_when_dst_full: bool = False @dataclass class Plotting: diff --git a/src/plotman/manager.py b/src/plotman/manager.py index e6a98585..6b3e2222 100644 --- a/src/plotman/manager.py +++ b/src/plotman/manager.py @@ -84,21 +84,23 @@ def maybe_start_new_plot(dir_cfg, sched_cfg, plotting_cfg): if phases_permit_new_job(phases, d, sched_cfg, dir_cfg) ] rankable = [ (d, phases[0]) if phases else (d, (999, 999)) for (d, phases) in eligible ] - - if not eligible: + dir2ph = {d: ph for (d, ph) in dstdirs_to_youngest_phase(jobs).items() + if (d in dir_cfg.dst and plot_util.is_valid_plot_dst(d, sched_cfg, jobs))} + unused_dirs = [d for d in dir_cfg.dst + if d not in dir2ph.keys() and plot_util.is_valid_plot_dst(d, sched_cfg, jobs)] + + if not unused_dirs and not dir2ph: + wait_reason = 'no eligible dstdirs' + elif not eligible: wait_reason = 'no eligible tempdirs' else: # Plot to oldest tmpdir. tmpdir = max(rankable, key=operator.itemgetter(1))[0] - # Select the dst dir least recently selected - dir2ph = { d:ph for (d, ph) in dstdirs_to_youngest_phase(jobs).items() - if d in dir_cfg.dst } - unused_dirs = [d for d in dir_cfg.dst if d not in dir2ph.keys()] - dstdir = '' - if unused_dirs: + if unused_dirs: dstdir = random.choice(unused_dirs) else: + # Select the dst dir least recently selected dstdir = max(dir2ph, key=dir2ph.get) logfile = os.path.join( diff --git a/src/plotman/plot_util.py b/src/plotman/plot_util.py index ca24ae08..7994a492 100644 --- a/src/plotman/plot_util.py +++ b/src/plotman/plot_util.py @@ -2,6 +2,8 @@ import os import re +from plotman import job + GB = 1_000_000_000 def df_b(d): @@ -12,6 +14,22 @@ def df_b(d): def get_k32_plotsize(): return 108 * GB +def is_valid_plot_dst(d, sched_cfg, all_jobs): + if sched_cfg.stop_when_dst_full: + space = df_b(d) + # Subtract space for current jobs which will be moved to the dir + # Note: This is underestimates the free space available when a + # job is in phase 4 since the plot is partially moved to dst, + # once phase 4 is complete a new plot will eventually kick off + jobs_to_dstdir = job.job_phases_for_dstdir(d, all_jobs) + space -= len(jobs_to_dstdir) * get_k32_plotsize() + return enough_space_for_k32(space) + return True + +def enough_space_for_k32(b): + 'Determine if there is enough space for a k32 given a number of free bytes' + return b > 1.2 * get_k32_plotsize() + def human_format(num, precision): magnitude = 0 while abs(num) >= 1000: diff --git a/src/plotman/resources/plotman.yaml b/src/plotman/resources/plotman.yaml index bdac9412..b3276e2a 100644 --- a/src/plotman/resources/plotman.yaml +++ b/src/plotman/resources/plotman.yaml @@ -109,6 +109,10 @@ scheduling: # How often the daemon wakes to consider starting a new plot job, in seconds. polling_time_s: 20 + # Stop initiating new plots when a dst is full, default to False since + # archiving job should move other plots before plotting is completed + stop_when_dst_full: False + # Plotting parameters. These are pass-through parameters to chia plots create. # See documentation at