Project

General

Profile

proposal-issue-minor-functional-5.txt

Sergey Ivanovskiy, 08/12/2026 04:15 PM

Download (5.94 KB)

 
1
================================================================================================
2
PROPOSAL - [MINOR] functional - PushMessagesWorker.getQueueSize
3
Dead method whose javadoc documents a guard that was never built
4
================================================================================================
5

    
6
REVIEW FINDING (abridged)
7
   "Newly added by this change with no caller anywhere in the tree [...] yet its javadoc asserts a
8
   use that does not exist: 'Used by the keep-alive timer to tell its own silence apart from a
9
   backlog' [...] The claim is not merely unimplemented but unimplementable as written."
10

    
11
FILES
12
   src/com/goldencode/p2j/ui/client/driver/web/PushMessagesWorker.java
13

    
14
------------------------------------------------------------------------------------------------
15
1. ROOT CAUSE
16
------------------------------------------------------------------------------------------------
17

    
18
The method (PushMessagesWorker.java:398-409) is added by this revision and has no caller anywhere -
19
grep across src/, test/ and tools/ finds only the declaration. Its javadoc nevertheless says:
20

    
21
   * Used by the keep-alive timer to tell its own silence apart from a backlog: while output is
22
   * queued the peer may simply not have been asked anything yet, so its silence proves nothing.
23

    
24
WebClientProtocol.startKeepAlivePing's TimerTask reads pushWorker only to call pushMessageFirst and
25
decides peer death purely from dataQuietMs >= dataIdleMs - tickMs. There is no backlog term.
26

    
27
The claim is not just unimplemented, it is unimplementable in this form, for two independent
28
reasons:
29

    
30
   (a) The premise is already false. pushMessageFirst (:280) enqueues the heartbeat with offerFirst
31
       and bypasses awaitCapacity entirely, so a deep queue cannot delay the ping behind it. The
32
       backlog the javadoc worries about does not in fact keep the peer from being asked.
33

    
34
   (b) The measurement would not see the case that matters. sendMessage polls the message off the
35
       deque *before* the blocking write, so during the only scenario that can genuinely starve the
36
       heartbeat - a stalled send, where the peer has stopped draining its socket - getQueueSize()
37
       reads 0. The proposed guard would be blind precisely when it was needed.
38

    
39
Separately, ConcurrentLinkedDeque.size() is a documented O(n) traversal, so it would be the wrong
40
primitive for a per-tick check even if a depth check were wanted.
41

    
42
Leaving this in place is a maintenance hazard rather than a runtime one: the next person to read
43
startKeepAlivePing will believe a backlog guard exists somewhere and reason about the heartbeat on
44
that basis.
45

    
46
------------------------------------------------------------------------------------------------
47
2. PROPOSED FIX
48
------------------------------------------------------------------------------------------------
49

    
50
2.1 Delete the method
51
-----------------------
52

    
53
   -  /**
54
   -   * The number of messages still waiting to be transmitted.
55
   -   * <p>
56
   -   * Used by the keep-alive timer to tell its own silence apart from a backlog: while output is
57
   -   * queued the peer may simply not have been asked anything yet, so its silence proves nothing.
58
   -   *
59
   -   * @return   The current depth of the outbound queue.
60
   -   */
61
   -  public int getQueueSize()
62
   -  {
63
   -     return messages.size();
64
   -  }
65

    
66
Nothing else changes; there are no callers to update. The class already exposes queue pressure where
67
it is genuinely needed, through awaitCapacity/queuedBytes, which is byte-based and O(1).
68

    
69
2.2 Record why, where the next reader will look
70
-------------------------------------------------
71

    
72
The reasoning above is worth keeping, but it belongs next to the decision it explains, not on a
73
deleted method. Add it to startKeepAlivePing's javadoc in WebClientProtocol, which already documents
74
the deadline design:
75

    
76
   +   * <p>
77
   +   * The deadline deliberately does not consider the outbound queue depth.  A backlog cannot delay
78
   +   * the heartbeat - {@link PushMessagesWorker#pushMessageFirst} enqueues it at the head and skips
79
   +   * the backpressure gate - and the one condition that can starve it, a send stalled on a peer
80
   +   * that has stopped reading, leaves the queue reading empty because the message has already been
81
   +   * polled off it.  A peer that has not accepted a byte for a whole deadline is correctly closed.
82

    
83
2.3 If a backlog guard is actually wanted
84
-------------------------------------------
85

    
86
It should not be built on queue depth. The measurable signal is *completed writes*: a monotonic
87
counter incremented in sendMessage after a successful send would distinguish "the socket is still
88
draining, the page is just behind" from "nothing is moving at all", and unlike queue depth it is not
89
blind to the in-flight message. That is a design change to the deadline, not a javadoc fix, and
90
should be raised as its own task with a stated failure case; it is out of scope here.
91

    
92
------------------------------------------------------------------------------------------------
93
3. RELATIONSHIP TO OTHER PROPOSALS
94
------------------------------------------------------------------------------------------------
95

    
96
None. This is self-contained.
97

    
98
Note for the history block: the method was added under entry 010 in this same revision, so removing
99
it needs no new history entry if the change is folded into the same commit; if it lands separately,
100
add one rather than editing 010.
101

    
102
------------------------------------------------------------------------------------------------
103
4. RISK AND VERIFICATION
104
------------------------------------------------------------------------------------------------
105

    
106
Risk: none. The method is unreferenced.
107

    
108
Verification
109
   1. grep -rn "getQueueSize" src/ test/ tools/ returns nothing after the change.
110
   2. ./gradlew compile succeeds.
111
   3. Confirm no rules/ TRPL or reflection-based lookup names the method (grep the whole tree, not
112
      just the Java source) - it is a public method on a public class, so this is worth one check
113
      even though no such usage is plausible.