From 2d2ff221926bb11bfe5d544dc1fbd558fab89f10 Mon Sep 17 00:00:00 2001 From: Jean-Paul Calderone <exarkun@twistedmatrix.com> Date: Mon, 15 Nov 2021 15:19:40 -0500 Subject: [PATCH] pick the right share to use for lease renewal decisions now that the server actually returns different info for different shares, we can, and we should, and we must --- src/_zkapauthorizer/lease_maintenance.py | 25 +++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/_zkapauthorizer/lease_maintenance.py b/src/_zkapauthorizer/lease_maintenance.py index 8858c91..e8e76cd 100644 --- a/src/_zkapauthorizer/lease_maintenance.py +++ b/src/_zkapauthorizer/lease_maintenance.py @@ -206,12 +206,31 @@ def renew_leases_on_server( # Keep track of what's been seen. activity.observe([stat.size for stat in stat_dict.values()]) - # All shares have the same lease information. - stat = stat_dict.popitem()[1] - if needs_lease_renew(min_lease_remaining, stat, now): + # Each share has its own leases and each lease has its own expiration + # time. For each share the server only returns the lease with the + # expiration time farthest in the future. + # + # There is no API for renewing leases on just *some* shares! It is + # all or nothing. So from the server's response we find the share + # that will have no active lease soonest and make our decision about + # whether to renew leases at this storage index or not based on that. + most_endangered = soonest_expiration(stat_dict.values()) + if needs_lease_renew(min_lease_remaining, most_endangered, now): yield renew_lease(renewal_secret, cancel_secret, storage_index, server) +def soonest_expiration(stats): + # type: (Iterable[ShareStat]) -> ShareStat + """ + :return: The share stat from ``stats`` all the leases of which will expire + soonest. + """ + return min( + stats, + key=lambda stat: stat.lease_expiration, + ) + + def renew_lease(renewal_secret, cancel_secret, storage_index, server): """ Renew the lease on the shares in one storage index on one server. -- GitLab