package waymaker.top.android; // Copyright © 2015 Michael Allan. Licence MIT. import java.util.Map; import waymaker.gen.ThreadSafe; import waymaker.spec.*; /** A pollar count at the remote count server. */ public final @ThreadSafe class ServerCount { /** Asynchronously requests the initial data for a group of peers. The result set will include all * major peers of the group, if any. Optionally it may be padded with minor peers to a convenient * size. Subsequent {@linkplain #enqueuePeersRequest(VotingID,PeersReceiver,int,int) range * requests} may be used to complete the data, as necessary. * * @param rootwardID The identity of the common node immediately to the rootward of the * peers, or null if the peers themselves are roots. * @param receiver The agent to handle any eventual response from the remote count server; * normally this will be either the {@linkplain Forest#receivePeersResponse(Object) * forest}, or an intermediary that delegates to it. * @param paddedLimit The maximum size of the result set when padded by minor peers, or zero to * prevent any such padding. The actual size may exceed the paddedLimit when the result set * comprises major peers alone, in which case the absolute size limit is determined by the * count engine’s definition of ‘major’ versus ‘minor’. * * @throws IllegalArgumentException if paddedLimit is less than zero. * * @see ‘peer’ */ public void enqueuePeersRequest( final VotingID rootwardID, final PeersReceiver receiver, final int paddedLimit ) { if( paddedLimit < 0 ) throw new IllegalArgumentException(); receiver.receivePeersResponse( rootwardID ); // sending an immediate default response in lieu of a real response from the remote server } /* * * - count server may implement by querying for all peers of ordinal <= paddedLimit - then calculate from result count the highest ordinal to return, and immediately stream the response by filtering out any higher ones - major/minor distinction in count engine - purpose is to enable efficient paging together with a rough sorting - initial page contains all major peers - client can present these in sorted order as desired - subsequent pages contain only minor, relatively uninteresting peers - no matter then if client presents page boundaries to user for paging convenience, rather than attempt a total sorting of all peers across all pages - maintenance - calculate threshold as gFlow/128 (integer) - where gFlow is total flow of peer group ( for voter group, inflow of candidate ( for root group, total inflow of roots, viz. turnout ( not using ground flow registers to calculate turnout, notebook 2015.9.30 - major node has inflow > threshold - as threshold changes it should be easy to isolate range of nodes affected by change and adjust their peer ordinals accordingly */ /** Asynchronously requests the data for a range of minor peers. The order of peers in the result * set is undefined. * * @param rootwardID The identity of the node immediately to the rootward, or null if the * peers themselves are roots. * @param receiver The agent to handle any eventual response from the remote count server; normally * this will be either the {@linkplain Forest#receivePeersResponse(Object) forest}, or an * intermediary that delegates to it. * @param peersStart The start ordinal of the range, inclusive. * @param peersEndBound The end ordinal of the range, exclusive. * * @throws IndexOutOfBoundsException if pStart is less than 1 or greater than pEndBound. */ public void enqueuePeersRequest( VotingID rootwardID, PeersReceiver receiver, int peersStart, int peersEndBound ) { if( peersStart < 1 || peersStart > peersEndBound ) throw new IndexOutOfBoundsException(); // WaykitUI.setRemotelyUsable(); /// when this is coded throw new UnsupportedOperationException( "Server counts not yet coded" ); } /* * * - maintenance of ordinals for minor peers in count engine - kept unique and contiguous with minimal effort - deletion of minor accomplished by swapping in final minor - requires tracking highest ordinal ( stored in candidate node for voters | in poll-wide store for roots - an upper limit (< Integer.MAX_VALUE) is imposed - thence all remaining peers share same ordinal ( not worth using long values here when the only purpose is paging in UI */ /** Synchronously connects to the remote count server and returns from the latest count the identified * node complete with its {@linkplain CountNode#rootwardInThis() candidates}, constructing those too as * necessary; or returns null if the node is uncounted there. * * @see CountNode#id() * @param nodeMap A map of nodes keyed by identity tag. Any candidate in the map is reused * rather than constructed anew, while all newly constructed candidates are added to the map. * * @throws AssertionError if assertions are enabled and nodeMap already keys the given tag. */ public UnadjustedNode fetchNode( final VotingID id, final Map nodeMap ) { assert !nodeMap.containsKey(id): "Not fetching an already fetched node"; return null; // server counts not yet coded // will also have to detect and throw exception on serial inconsitency (RepocastSer) } /** Answers whether the given string is a well formed poll name, that is a well formed rep * {@linkplain ID#isSerialForm(String) serial number}. */ public static boolean isPollNameForm( final String string ) { return ID.isSerialForm( string ); } }