From ddc9af0ddfd27bcbd890ae4593dbaad0c816b817 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Fri, 12 Aug 2022 23:53:02 +0100 Subject: [PATCH] Add docstrings to chankeep --- modules/chankeep.py | 116 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 17 deletions(-) diff --git a/modules/chankeep.py b/modules/chankeep.py index 5abcb8f..85865f2 100644 --- a/modules/chankeep.py +++ b/modules/chankeep.py @@ -10,6 +10,11 @@ from utils.logging.log import error, log, warn def getActiveRelays(net): + """ + Get a list of active relays for a network. + :param net: network + :rtype: list of int + :return: list of active relay numbers""" activeRelays = [x for x in main.network[net].relays.keys() if main.network[net].relays[x]["enabled"]] return activeRelays @@ -17,6 +22,9 @@ def getActiveRelays(net): def allRelaysActive(net): """ Check if all enabled relays are active and authenticated. + :param net: network + :rtype: bool + :return: True if all relays are active and authenticated, False otherwise """ activeRelays = getActiveRelays(net) debug(f"allRelaysActive() active relays for {net}: {activeRelays}") @@ -62,6 +70,12 @@ def getChanFree(net, new): def getTotalChans(net): + """ + Get the total number of channels on all relays for a network. + :param net: network + :rtype: int + :return: total number of channels + """ total = 0 for i in getActiveRelays(net): name = net + str(i) @@ -71,16 +85,31 @@ def getTotalChans(net): def emptyChanAllocate(net, flist, new): + """ + Allocate channels to relays. + :param net: network + :param flist: list of channels to allocate + :param new: list of newly provisioned relays to account for + :rtype: dict + :return: dictionary of {relay: list of channels}""" + + # Get the free channel spaces for each relay chanfree = getChanFree(net, new) if not chanfree: return + + # Pretend the newly provisioned relays are already on the network for i in new: chanfree[0][i] = chanfree[1] allocated = {} + + # Copy the list since we're going to mutate it toalloc = len(flist) + # Used to correct allocations and provision additional relays # if the math since the last LIST is a bit wrong # toalloc:2148 free:{1: 250} chanlimit:250 correction:2147 + newlist = list(flist) if toalloc > sum(chanfree[0].values()): sum_free = sum(chanfree[0].values()) # 250 chans_not_covered = toalloc - sum_free # 2148 - 250 = 1898 @@ -108,10 +137,9 @@ def emptyChanAllocate(net, flist, new): # Let's do the best we can in the circumstances. debug(f"emptyChanAllocate() cannot create additional relays for {net}") debug(f"emptyChanAllocate() {chans_not_covered} channels cannot be covered") - flist = flist[:sum_free] + newlist = newlist[:sum_free] debug(f"emptyChanAllocate() flist truncated to {sum_free}, length nis now {len(flist)}") trace(f"emptyChanAllocate() best effort allocation: {flist}") - newlist = list(flist) for i in chanfree[0].keys(): for x in range(chanfree[0][i]): if not len(newlist): @@ -124,6 +152,12 @@ def emptyChanAllocate(net, flist, new): def populateChans(net, clist, new): + """ + Populate channels on relays. + Stores channels to join in a list in main.TempChan[net][num] + :param net: network + :param clist: list of channels to join + :param new: list of newly provisioned relays to account for""" # divided = array_split(clist, relay) allocated = emptyChanAllocate(net, clist, new) if not allocated: @@ -136,6 +170,11 @@ def populateChans(net, clist, new): def notifyJoin(net): + """ + Notify relays to join channels. + They will pull from main.TempChan and remove channels they join. + :param net: network + """ for i in getActiveRelays(net): name = net + str(i) if name in main.IRCPool.keys(): @@ -143,6 +182,14 @@ def notifyJoin(net): def minifyChans(net, listinfo): + """ + Remove channels from listinfo that are already covered by a relay. + :param net: network + :param listinfo: list of channels to check + :type listinfo: list of [channel, num_users] + :return: list of channels with joined channels removed + :rtype: list of [channel, num_users] + """ if not allRelaysActive(net): error("All relays for %s are not active, cannot minify list" % net) return False @@ -159,6 +206,19 @@ def minifyChans(net, listinfo): def keepChannels(net, listinfo, mean, sigrelay, relay, chanlimit): + """ + Minify channels, determine whether we can cover all the channels + on the network, or need to use 'significant' mode. + Truncate the channel list to available channel spaces. + Allocate these channels to relays. + Notify relays that they should pull from TempChan to join. + :param net: network + :param listinfo: list of [channel, num_users] lists + :param mean: mean of channel population + :param sigrelay: number of relays needed to cover significant channels + :param relay: number of relays needed to cover all channels + :param chanlimit: maximum number of channels to allocate to a relay + """ listinfo = minifyChans(net, listinfo) if not listinfo: return @@ -193,6 +253,14 @@ def keepChannels(net, listinfo, mean, sigrelay, relay, chanlimit): def joinSingle(net, channel): + """ + Join a channel on a relay. + Use ECA to determine which relay to join on. + :param net: network + :param channel: channel to join + :return: relay number that joined the channel + :rtype: int + """ eca = emptyChanAllocate(net, [channel], []) if not eca: return False @@ -209,9 +277,10 @@ def joinSingle(net, channel): def partSingle(net, channel): """ Iterate over all the relays of net and part channels matching channel. - :param net: - :param channel: - :return: + :param net: network + :param channel: channel to part + :return: list of relays that parted the channel + :rtype: list of str """ parted = [] for i in getActiveRelays(net): @@ -224,6 +293,9 @@ def partSingle(net, channel): def nukeNetwork(net): + """ + Remove network records. + :param net: network""" # purgeRecords(net) # p = main.g.pipeline() main.g.delete("analytics.list." + net) @@ -236,6 +308,21 @@ def nukeNetwork(net): def _initialList(net, num, listinfo, chanlimit): + """ + Called when a relay receives a full LIST response. + Run statistics to determine how many channels are significant. + This is done by adding all the numbers of users on the channels together, + then dividing by the number of channels. + * cumul - cumulative sum of all channel membership + * siglength - number of significant channels + * listlength - number of channels in the list + * sigrelay - number of relays needed to cover siglength + * relay - number of relays needed to cover all channels + :param net: network + :param num: relay number + :param listinfo: list of [channel, num_users] lists + :param chanlimit: maximum number of channels the relay can join + """ listlength = len(listinfo) cumul = 0 try: @@ -258,9 +345,11 @@ def _initialList(net, num, listinfo, chanlimit): sigrelay = ceil(siglength / chanlimit) relay = ceil(listlength / chanlimit) - # netbase = "list.%s" % net + abase = "analytics.list.%s" % net p = main.g.pipeline() + + # See docstring for meanings p.hset(abase, "mean", mean) p.hset(abase, "total", listlength) p.hset(abase, "sigtotal", siglength) @@ -296,16 +385,9 @@ def _initialList(net, num, listinfo, chanlimit): def initialList(net, num, listinfo, chanlimit): + """ + Run _initialList in a thread. + See above docstring. + """ deferToThread(_initialList, net, num, deepcopy(listinfo), chanlimit) - -def chankeep_handler(net, num, listinfo, chanlimit): - """ - Handle a channel keep request. - :param net: - :param num: - :param listinfo: - :param chanlimit: - :return: - """ - listinfo, mean, sigrelay, relay = _initialList(net, num, listinfo, chanlimit)