You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2023/01/20 19:04:56 UTC

[tomcat] 07/12: Implement new allocation algorithm

This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 14d3637bec7708d6a359165db889b6362d03925a
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Dec 7 11:14:46 2022 +0000

    Implement new allocation algorithm
    
    Currently using defaults as priorities aren't read yet.
---
 .../apache/coyote/http2/AbstractNonZeroStream.java |  55 +---
 java/org/apache/coyote/http2/AbstractStream.java   |  47 ----
 java/org/apache/coyote/http2/Constants.java        |   6 +-
 .../apache/coyote/http2/Http2UpgradeHandler.java   | 310 +++++++--------------
 .../apache/coyote/http2/LocalStrings.properties    |   2 -
 .../apache/coyote/http2/LocalStrings_cs.properties |   1 -
 .../apache/coyote/http2/LocalStrings_es.properties |   2 -
 .../apache/coyote/http2/LocalStrings_fr.properties |   2 -
 .../apache/coyote/http2/LocalStrings_ja.properties |   2 -
 .../apache/coyote/http2/LocalStrings_ko.properties |   2 -
 .../coyote/http2/LocalStrings_zh_CN.properties     |   2 -
 java/org/apache/coyote/http2/Stream.java           |  24 +-
 12 files changed, 129 insertions(+), 326 deletions(-)

diff --git a/java/org/apache/coyote/http2/AbstractNonZeroStream.java b/java/org/apache/coyote/http2/AbstractNonZeroStream.java
index 0876fc88c6..5a9c3e3a48 100644
--- a/java/org/apache/coyote/http2/AbstractNonZeroStream.java
+++ b/java/org/apache/coyote/http2/AbstractNonZeroStream.java
@@ -17,7 +17,6 @@
 package org.apache.coyote.http2;
 
 import java.nio.ByteBuffer;
-import java.util.Iterator;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -36,8 +35,6 @@ abstract class AbstractNonZeroStream extends AbstractStream {
 
     protected final StreamStateMachine state;
 
-    private volatile int weight = Constants.DEFAULT_WEIGHT;
-
 
     AbstractNonZeroStream(String connectionId, Integer identifier) {
         super(identifier);
@@ -51,12 +48,6 @@ abstract class AbstractNonZeroStream extends AbstractStream {
     }
 
 
-    @Override
-    final int getWeight() {
-        return weight;
-    }
-
-
     /*
      * General method used when reprioritising a stream and care needs to be
      * taken not to create circular references.
@@ -71,27 +62,7 @@ abstract class AbstractNonZeroStream extends AbstractStream {
                     parent.getIdAsString(), Integer.toString(weight)));
         }
 
-        // Check if new parent is a descendant of this stream
-        if (isDescendant(parent)) {
-            parent.detachFromParent();
-            // Cast is always safe since any descendant of this stream must be
-            // an instance of AbstractNonZeroStream
-            getParentStream().addChild((AbstractNonZeroStream) parent);
-        }
-
-        if (exclusive) {
-            // Need to move children of the new parent to be children of this
-            // stream. Slightly convoluted to avoid concurrent modification.
-            Iterator<AbstractNonZeroStream> parentsChildren = parent.getChildStreams().iterator();
-            while (parentsChildren.hasNext()) {
-                AbstractNonZeroStream parentsChild = parentsChildren.next();
-                parentsChildren.remove();
-                this.addChild(parentsChild);
-            }
-        }
-        detachFromParent();
-        parent.addChild(this);
-        this.weight = weight;
+        // TODO
     }
 
 
@@ -109,29 +80,7 @@ abstract class AbstractNonZeroStream extends AbstractStream {
                     parent.getIdAsString(), Integer.toString(weight)));
         }
 
-        parent.addChild(this);
-        this.weight = weight;
-    }
-
-
-    /*
-     * Used when "recycling" a stream and replacing a Stream instance with a
-     * RecycledStream instance.
-     *
-     * Replace this stream with the provided stream in the parent/child
-     * hierarchy.
-     *
-     * Changes to the priority tree need to be synchronized at the connection
-     * level. This is the caller's responsibility.
-     */
-    void replaceStream(AbstractNonZeroStream replacement) {
-        getParentStream().addChild(replacement);
-        detachFromParent();
-        for (AbstractNonZeroStream child : getChildStreams()) {
-            replacement.addChild(child);
-        }
-        getChildStreams().clear();
-        replacement.weight = weight;
+        // TODO
     }
 
 
diff --git a/java/org/apache/coyote/http2/AbstractStream.java b/java/org/apache/coyote/http2/AbstractStream.java
index dc651d30e9..d3533c5bd8 100644
--- a/java/org/apache/coyote/http2/AbstractStream.java
+++ b/java/org/apache/coyote/http2/AbstractStream.java
@@ -16,9 +16,6 @@
  */
 package org.apache.coyote.http2;
 
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.res.StringManager;
@@ -35,8 +32,6 @@ abstract class AbstractStream {
     private final Integer identifier;
     private final String idAsString;
 
-    private volatile AbstractStream parentStream = null;
-    private final Set<AbstractNonZeroStream> childStreams = ConcurrentHashMap.newKeySet();
     private long windowSize = ConnectionSettingsBase.DEFAULT_INITIAL_WINDOW_SIZE;
 
     private volatile int connectionAllocationRequested = 0;
@@ -64,46 +59,6 @@ abstract class AbstractStream {
     }
 
 
-    final void detachFromParent() {
-        if (parentStream != null) {
-            parentStream.getChildStreams().remove(this);
-            parentStream = null;
-        }
-    }
-
-
-    final void addChild(AbstractNonZeroStream child) {
-        child.setParentStream(this);
-        childStreams.add(child);
-    }
-
-
-    final boolean isDescendant(AbstractStream stream) {
-        // Is the passed in Stream a descendant of this Stream?
-        // Start at the passed in Stream and work up
-        AbstractStream parent = stream.getParentStream();
-        while (parent != null && parent != this) {
-            parent = parent.getParentStream();
-        }
-        return parent != null;
-    }
-
-
-    final AbstractStream getParentStream() {
-        return parentStream;
-    }
-
-
-    final void setParentStream(AbstractStream parentStream) {
-        this.parentStream = parentStream;
-    }
-
-
-    final Set<AbstractNonZeroStream> getChildStreams() {
-        return childStreams;
-    }
-
-
     final synchronized void setWindowSize(long windowSize) {
         this.windowSize = windowSize;
     }
@@ -181,6 +136,4 @@ abstract class AbstractStream {
 
 
     abstract String getConnectionId();
-
-    abstract int getWeight();
 }
diff --git a/java/org/apache/coyote/http2/Constants.java b/java/org/apache/coyote/http2/Constants.java
index 739ae7eb12..e1ee63bb34 100644
--- a/java/org/apache/coyote/http2/Constants.java
+++ b/java/org/apache/coyote/http2/Constants.java
@@ -19,7 +19,11 @@ package org.apache.coyote.http2;
 public class Constants {
 
     // Prioritisation
-    public static final int DEFAULT_WEIGHT = 16;
+    public static final int DEFAULT_URGENCY = 3;
+    public static final boolean DEFAULT_INCREMENTAL = false;
+    // Range 0 to 7 inclusive
+    public static final int URGENCY_RANGE = 8;
+
 
     // Parsing
     static final int DEFAULT_HEADER_READ_BUFFER_SIZE = 1024;
diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
index a2405994a8..a5ebde3b26 100644
--- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
+++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
@@ -20,15 +20,15 @@ import java.io.EOFException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Queue;
 import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ConcurrentNavigableMap;
 import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
@@ -94,8 +94,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
 
     private static final HeaderSink HEADER_SINK = new HeaderSink();
 
-    private final Object priorityTreeLock = new Object();
-
     protected final String connectionId;
 
     protected final Http2Protocol protocol;
@@ -131,7 +129,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
     private final AtomicInteger nextLocalStreamId = new AtomicInteger(2);
     private final PingManager pingManager = getPingManager();
     private volatile int newStreamsSinceLastPrune = 0;
-    private final Set<AbstractStream> backLogStreams = ConcurrentHashMap.newKeySet();
+    private final Set<Stream> backLogStreams = new HashSet<>();
     private long backLogSize = 0;
     // The time at which the connection will timeout unless data arrives before
     // then. -1 means no timeout.
@@ -954,11 +952,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
                         stream.setConnectionAllocationRequested(reservation);
                         backLogSize += reservation;
                         backLogStreams.add(stream);
-                        // Add the parents as well
-                        AbstractStream parent = stream.getParentStream();
-                        while (parent != null && backLogStreams.add(parent)) {
-                            parent = parent.getParentStream();
-                        }
                     }
                 } else if (windowSize < reservation) {
                     allocation = (int) windowSize;
@@ -1070,8 +1063,7 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
 
     private synchronized Set<AbstractStream> releaseBackLog(int increment) throws Http2Exception {
         Set<AbstractStream> result = new HashSet<>();
-        int remaining = increment;
-        if (backLogSize < remaining) {
+        if (backLogSize < increment) {
             // Can clear the whole backlog
             for (AbstractStream stream : backLogStreams) {
                 if (stream.getConnectionAllocationRequested() > 0) {
@@ -1079,23 +1071,90 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
                     stream.setConnectionAllocationRequested(0);
                 }
             }
-            remaining -= backLogSize;
+            // Cast is safe due to test above
+            int remaining = increment - (int) backLogSize;
             backLogSize = 0;
             super.incrementWindowSize(remaining);
 
             result.addAll(backLogStreams);
             backLogStreams.clear();
         } else {
-            allocate(this, remaining);
-            Iterator<AbstractStream> streamIter = backLogStreams.iterator();
-            while (streamIter.hasNext()) {
-                AbstractStream stream = streamIter.next();
-                if (stream.getConnectionAllocationMade() > 0) {
-                    backLogSize -= stream.getConnectionAllocationMade();
-                    backLogSize -= stream.getConnectionAllocationRequested();
-                    stream.setConnectionAllocationRequested(0);
-                    result.add(stream);
-                    streamIter.remove();
+            // Can't clear the whole backlog.
+            // Need streams in priority order
+            Set<Stream> orderedStreams = new ConcurrentSkipListSet<>(Comparator.comparingInt(Stream::getUrgency)
+                    .thenComparing(Stream::getIncremental).thenComparing(Stream::getIdAsInt));
+            orderedStreams.addAll(backLogStreams);
+
+            // Iteration 1. Need to work out how much we can clear.
+            long urgencyWhereAllocationIsExhausted = 0;
+            long requestedAllocationForIncrementalStreams = 0;
+            int remaining = increment;
+            Iterator<Stream> orderedStreamsIterator = orderedStreams.iterator();
+            while (orderedStreamsIterator.hasNext()) {
+                Stream s = orderedStreamsIterator.next();
+                if (urgencyWhereAllocationIsExhausted < s.getUrgency()) {
+                    if (remaining < 1) {
+                        break;
+                    }
+                    requestedAllocationForIncrementalStreams = 0;
+                }
+                urgencyWhereAllocationIsExhausted = s.getUrgency();
+                if (s.getIncremental()) {
+                    requestedAllocationForIncrementalStreams += s.getConnectionAllocationRequested();
+                    remaining -= s.getConnectionAllocationRequested();
+                } else {
+                    remaining -= s.getConnectionAllocationRequested();
+                    if (remaining < 1) {
+                        break;
+                    }
+                }
+            }
+
+            // Iteration 2. Allocate.
+            // Reset for second iteration
+            remaining = increment;
+            orderedStreamsIterator = orderedStreams.iterator();
+            while (orderedStreamsIterator.hasNext()) {
+                Stream s = orderedStreamsIterator.next();
+                if (s.getUrgency() < urgencyWhereAllocationIsExhausted) {
+                    // Can fully allocate
+                    remaining = allocate(s, remaining);
+                    result.add(s);
+                    orderedStreamsIterator.remove();
+                    backLogStreams.remove(s);
+                } else if (requestedAllocationForIncrementalStreams == 0) {
+                    // Allocation ran out in non-incremental streams so fully
+                    // allocate in iterator order until allocation is exhausted
+                    remaining = allocate(s, remaining);
+                    result.add(s);
+                    if (s.getConnectionAllocationRequested() == 0) {
+                        // Fully allocated
+                        orderedStreamsIterator.remove();
+                        backLogStreams.remove(s);
+                    }
+                    if (remaining < 1) {
+                        break;
+                    }
+                } else {
+                    // Allocation ran out in incremental streams. Distribute
+                    // remaining allocation between the incremental streams at
+                    // this urgency level.
+                    if (s.getUrgency() != urgencyWhereAllocationIsExhausted) {
+                        break;
+                    }
+
+                    int share = (int) (s.getConnectionAllocationRequested() * remaining / requestedAllocationForIncrementalStreams);
+                    if (share == 0) {
+                        share = 1;
+                    }
+                    allocate(s, share);
+                    result.add(s);
+                    if (s.getConnectionAllocationRequested() == 0) {
+                        // Fully allocated (unlikely but possible due to
+                        // rounding if only a few bytes required).
+                        orderedStreamsIterator.remove();
+                        backLogStreams.remove(s);
+                    }
                 }
             }
         }
@@ -1123,67 +1182,12 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
             leftToAllocate = leftToAllocate - allocatedThisTime;
         }
 
-        if (leftToAllocate == 0) {
-            return 0;
-        }
-
         if (log.isDebugEnabled()) {
             log.debug(sm.getString("upgradeHandler.allocate.left",
                     getConnectionId(), stream.getIdAsString(), Integer.toString(leftToAllocate)));
         }
 
-        // Recipients are children of the current stream that are in the
-        // backlog.
-        Set<AbstractStream> recipients = new HashSet<>(stream.getChildStreams());
-        recipients.retainAll(backLogStreams);
-
-        // Loop until we run out of allocation or recipients
-        while (leftToAllocate > 0) {
-            if (recipients.size() == 0) {
-                if (stream.getConnectionAllocationMade() == 0) {
-                    backLogStreams.remove(stream);
-                }
-                if (stream.getIdAsInt() == 0) {
-                    throw new IllegalStateException();
-                }
-                return leftToAllocate;
-            }
-
-            int totalWeight = 0;
-            for (AbstractStream recipient : recipients) {
-                if (log.isDebugEnabled()) {
-                    log.debug(sm.getString("upgradeHandler.allocate.recipient",
-                            getConnectionId(), stream.getIdAsString(), recipient.getIdAsString(),
-                            Integer.toString(recipient.getWeight())));
-                }
-                totalWeight += recipient.getWeight();
-            }
-
-            // Use an Iterator so fully allocated children/recipients can be
-            // removed.
-            Iterator<AbstractStream> iter = recipients.iterator();
-            int allocated = 0;
-            while (iter.hasNext()) {
-                AbstractStream recipient = iter.next();
-                int share = leftToAllocate * recipient.getWeight() / totalWeight;
-                if (share == 0) {
-                    // This is to avoid rounding issues triggering an infinite
-                    // loop. It will cause a very slight over allocation but
-                    // HTTP/2 should cope with that.
-                    share = 1;
-                }
-                int remainder = allocate(recipient, share);
-                // Remove recipients that receive their full allocation so that
-                // they are excluded from the next allocation round.
-                if (remainder > 0) {
-                    iter.remove();
-                }
-                allocated += (share - remainder);
-            }
-            leftToAllocate -= allocated;
-        }
-
-        return 0;
+        return leftToAllocate;
     }
 
 
@@ -1289,7 +1293,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
         // maximum number of concurrent streams.
         long max = localSettings.getMaxConcurrentStreams();
 
-        // Only need ~+10% for streams that are in the priority tree,
         // Ideally need to retain information for a "significant" amount of time
         // after sending END_STREAM (RFC 7540, page 20) so we detect potential
         // connection error. 5x seems reasonable. The client will have had
@@ -1307,100 +1310,23 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
         }
 
         int toClose = size - (int) max;
-        if (toClose < 1) {
-            return;
-        }
 
-        // Need to try and close some streams.
-        // Try to close streams in this order
-        // 1. Completed streams used for a request with no children
-        // 2. Completed streams used for a request with children
-        // 3. Closed final streams
-        //
-        // The pruning halts as soon as enough streams have been pruned.
-
-        // Use these sets to track the different classes of streams
-        TreeSet<Integer> candidatesStepTwo = new TreeSet<>();
-        TreeSet<Integer> candidatesStepThree = new TreeSet<>();
-
-        // Step 1
-        // Iterator is in key order so we automatically have the oldest streams
-        // first
-        // Tests depend on parent/child relationship between streams so need to
-        // lock on priorityTreeLock to ensure a consistent view.
-        synchronized (priorityTreeLock) {
-            for (AbstractNonZeroStream stream : streams.values()) {
-                // Never remove active streams
-                if (stream instanceof Stream && ((Stream) stream).isActive()) {
-                    continue;
-                }
-
-                if (stream.isClosedFinal()) {
-                    // This stream went from IDLE to CLOSED and is likely to have
-                    // been created by the client as part of the priority tree.
-                    // Candidate for step 3.
-                    candidatesStepThree.add(stream.getIdentifier());
-                } else if (stream.getChildStreams().size() == 0) {
-                    // Prune it
-                    AbstractStream parent = stream.getParentStream();
-                    streams.remove(stream.getIdentifier());
-                    stream.detachFromParent();
-                    if (log.isDebugEnabled()) {
-                        log.debug(sm.getString("upgradeHandler.pruned", connectionId, stream.getIdAsString()));
-                    }
-                    if (--toClose < 1) {
-                        return;
-                    }
-
-                    // If removing this child made the parent childless then see if
-                    // the parent can be removed.
-                    // Don't try and remove Stream 0 as that is the connection
-                    // Don't try and remove 'newer' streams. We'll get to them as we
-                    // work through the ordered list of streams.
-                    while (toClose > 0 && parent.getIdAsInt() > 0 && parent.getIdAsInt() < stream.getIdAsInt() &&
-                            parent.getChildStreams().isEmpty()) {
-                        // This cast is safe since we know parent ID > 0 therefore
-                        // this isn't the connection
-                        stream = (AbstractNonZeroStream) parent;
-                        parent = stream.getParentStream();
-                        streams.remove(stream.getIdentifier());
-                        stream.detachFromParent();
-                        if (log.isDebugEnabled()) {
-                            log.debug(sm.getString("upgradeHandler.pruned", connectionId, stream.getIdAsString()));
-                        }
-                        if (--toClose < 1) {
-                            return;
-                        }
-                        // Also need to remove this stream from the step 2 list
-                        candidatesStepTwo.remove(stream.getIdentifier());
-                    }
-                } else {
-                    // Closed, with children. Candidate for step 2.
-                    candidatesStepTwo.add(stream.getIdentifier());
-                }
-            }
-        }
-
-        // Process the P2 list
-        for (Integer streamIdToRemove : candidatesStepTwo) {
-            removeStreamFromPriorityTree(streamIdToRemove);
-            if (log.isDebugEnabled()) {
-                log.debug(sm.getString("upgradeHandler.pruned", connectionId, streamIdToRemove));
-            }
-            if (--toClose < 1) {
+        // Need to try and prune some streams. Prune streams starting with the
+        // oldest. Pruning stops as soon as enough streams have been pruned.
+        // Iterator is in key order.
+        for (AbstractNonZeroStream stream : streams.values()) {
+            if (toClose < 1) {
                 return;
             }
-        }
-
-        while (toClose > 0 && candidatesStepThree.size() > 0) {
-            Integer streamIdToRemove = candidatesStepThree.pollLast();
-            removeStreamFromPriorityTree(streamIdToRemove);
-            if (log.isDebugEnabled()) {
-                log.debug(sm.getString("upgradeHandler.prunedPriority", connectionId, streamIdToRemove));
+            if (stream instanceof Stream && ((Stream) stream).isActive()) {
+                continue;
             }
-            if (--toClose < 1) {
-                return;
+            streams.remove(stream.getIdentifier());
+            toClose--;
+            if (log.isDebugEnabled()) {
+                log.debug(sm.getString("upgradeHandler.pruned", connectionId, stream.getIdAsString()));
             }
+
         }
 
         if (toClose > 0) {
@@ -1410,33 +1336,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
     }
 
 
-    private void removeStreamFromPriorityTree(Integer streamIdToRemove) {
-        synchronized (priorityTreeLock) {
-            AbstractNonZeroStream streamToRemove = streams.remove(streamIdToRemove);
-            // Move the removed Stream's children to the removed Stream's
-            // parent.
-            Set<AbstractNonZeroStream> children = streamToRemove.getChildStreams();
-            if (children.size() == 1) {
-                // Shortcut
-                children.iterator().next().rePrioritise(
-                        streamToRemove.getParentStream(), streamToRemove.getWeight());
-            } else {
-                int totalWeight = 0;
-                for (AbstractNonZeroStream child : children) {
-                    totalWeight += child.getWeight();
-                }
-                for (AbstractNonZeroStream child : children) {
-                    children.iterator().next().rePrioritise(
-                            streamToRemove.getParentStream(),
-                            streamToRemove.getWeight() * child.getWeight() / totalWeight);
-                }
-            }
-            streamToRemove.detachFromParent();
-            children.clear();
-        }
-    }
-
-
     void push(Request request, Stream associatedStream) throws IOException {
         if (localSettings.getMaxConcurrentStreams() < activeRemoteStreamCount.incrementAndGet()) {
             // If there are too many open streams, simply ignore the push
@@ -1471,12 +1370,6 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
     }
 
 
-    @Override
-    protected final int getWeight() {
-        return 0;
-    }
-
-
     private void reduceOverheadCount(FrameType frameType) {
         // A non-overhead frame reduces the overhead count by
         // Http2Protocol.DEFAULT_OVERHEAD_REDUCTION_FACTOR. A simple browser
@@ -1909,15 +1802,10 @@ class Http2UpgradeHandler extends AbstractStream implements InternalHttpUpgradeH
 
 
     void replaceStream(AbstractNonZeroStream original, AbstractNonZeroStream replacement) {
-        synchronized (priorityTreeLock) {
-            AbstractNonZeroStream current = streams.get(original.getIdentifier());
-            // Might already have been recycled or removed from the priority
-            // tree entirely. Only replace it if the full stream is still in the
-            // priority tree.
-            if (current instanceof Stream) {
-                streams.put(original.getIdentifier(), replacement);
-                original.replaceStream(replacement);
-            }
+        AbstractNonZeroStream current = streams.get(original.getIdentifier());
+        // Only replace the stream if it currently uses the full implementation.
+        if (current instanceof Stream) {
+            streams.put(original.getIdentifier(), replacement);
         }
     }
 
diff --git a/java/org/apache/coyote/http2/LocalStrings.properties b/java/org/apache/coyote/http2/LocalStrings.properties
index 547a1880d1..3670d60f42 100644
--- a/java/org/apache/coyote/http2/LocalStrings.properties
+++ b/java/org/apache/coyote/http2/LocalStrings.properties
@@ -127,7 +127,6 @@ streamStateMachine.invalidFrame=Connection [{0}], Stream [{1}], State [{2}], Fra
 
 upgradeHandler.allocate.debug=Connection [{0}], Stream [{1}], allocated [{2}] bytes
 upgradeHandler.allocate.left=Connection [{0}], Stream [{1}], [{2}] bytes unallocated - trying to allocate to children
-upgradeHandler.allocate.recipient=Connection [{0}], Stream [{1}], potential recipient [{2}] with weight [{3}]
 upgradeHandler.connectionError=Connection error
 upgradeHandler.fallToDebug=\n\
 \ Note: further occurrences of HTTP/2 stream errors will be logged at DEBUG level.
@@ -144,7 +143,6 @@ upgradeHandler.prefaceReceived=Connection [{0}], Connection preface received fro
 upgradeHandler.pruneIncomplete=Connection [{0}], Stream [{1}], Failed to fully prune the connection because there are [{2}] too many active streams
 upgradeHandler.pruneStart=Connection [{0}] Starting pruning of old streams. Limit is [{1}] and there are currently [{2}] streams.
 upgradeHandler.pruned=Connection [{0}] Pruned completed stream [{1}]
-upgradeHandler.prunedPriority=Connection [{0}] Pruned unused stream [{1}] that may have been part of the priority tree
 upgradeHandler.releaseBacklog=Connection [{0}], Stream [{1}] released from backlog
 upgradeHandler.reset.receive=Connection [{0}], Stream [{1}], Reset received due to [{2}]
 upgradeHandler.enableRfc7450Priorities=Connection [{0}], RFC 7450 priorities may not be enabled after being disabled in the initial connection settings frame (see RFC 9218)
diff --git a/java/org/apache/coyote/http2/LocalStrings_cs.properties b/java/org/apache/coyote/http2/LocalStrings_cs.properties
index 88e888b023..b07e9902d1 100644
--- a/java/org/apache/coyote/http2/LocalStrings_cs.properties
+++ b/java/org/apache/coyote/http2/LocalStrings_cs.properties
@@ -31,7 +31,6 @@ http2Parser.processFramePushPromise=Connection [{0}], Stream [{1}], Rámec pro P
 upgradeHandler.pingFailed=Spojení [{0}] pro odeslání příkazu ping na klienta selhalo
 upgradeHandler.prefaceReceived=Spojení [{0}], přírava spojení přijata od klienta
 upgradeHandler.pruneIncomplete=Plné omezení spojení [{0}] selhalo, neboť streamy byly aktivní / použité v prioritním stromu. Existuje [{2}] příliš mnoho streamů
-upgradeHandler.prunedPriority=Spojení [{0}] omezilo nepoužívaný stream [{1}], který mohl být částí prioritního stromu
 upgradeHandler.rst.debug=Spojení [{0}], Stream [{1}], Chyba [{2}], Zpráva [{3}],  RST (zavírání streamu)
 upgradeHandler.sendPrefaceFail=Spojení [{0}], selhalo odeslánízahájení klientovi
 upgradeHandler.socketCloseFailed=Chyba zavírání socketu
diff --git a/java/org/apache/coyote/http2/LocalStrings_es.properties b/java/org/apache/coyote/http2/LocalStrings_es.properties
index acd5243110..2664cc5f8c 100644
--- a/java/org/apache/coyote/http2/LocalStrings_es.properties
+++ b/java/org/apache/coyote/http2/LocalStrings_es.properties
@@ -44,12 +44,10 @@ streamProcessor.error.connection=Conexión [{0}], Flujo [{1}], Ha ocurrido un er
 streamStateMachine.debug.change=Conexión [{0}], Flujo [{1}], Estado cambió de [{2}] a [{3}]
 
 upgradeHandler.allocate.left=Conexión [{0}], Flujo [{1}], [{2}] bytes no asignados -  tratando de asignar en el hijo
-upgradeHandler.allocate.recipient=Conexión [{0}], Flujo [{1}], recipiente potencial [{2}] con peso [{3}]
 upgradeHandler.ioerror=Conexión [{0}]
 upgradeHandler.pingFailed=Conexión [{0}] falló al hacer ping al cliente
 upgradeHandler.prefaceReceived=Conexión [{0}], Pre face de conexión recibida del cliente\n
 upgradeHandler.pruneIncomplete=La conexión [{0}] Falló al podar completamente la conexión porque existen flujos activos / usados en el árbol de priorida. Existen [{2}] muchos flujos
-upgradeHandler.prunedPriority=La conexión [{0}] ha cortado el flujo en desuso [{1}] el cual podía ser parte del árbol prioritario
 upgradeHandler.rst.debug=Conexión [{0}], Flujo [{1}], Error [{2}], Mensaje [{3}],  RST (cerrando flujo)
 upgradeHandler.sendPrefaceFail=La conexión [{0}], Falló al enviar el prefacio al cliente\n
 upgradeHandler.socketCloseFailed=Error cerrando el socket
diff --git a/java/org/apache/coyote/http2/LocalStrings_fr.properties b/java/org/apache/coyote/http2/LocalStrings_fr.properties
index e8551e4370..9044d4f47f 100644
--- a/java/org/apache/coyote/http2/LocalStrings_fr.properties
+++ b/java/org/apache/coyote/http2/LocalStrings_fr.properties
@@ -126,7 +126,6 @@ streamStateMachine.invalidFrame=Connection [{0}], Flux [{1}], Etat [{2}], Type d
 
 upgradeHandler.allocate.debug=Connection [{0}], Flux [{1}], [{2}] octets alloués
 upgradeHandler.allocate.left=Connection [{0}], Flux [{1}], [{2}] octets désalloués, essai d''allocation aux enfants
-upgradeHandler.allocate.recipient=Connection [{0}], Flux [{1}], receveur potentiel [{2}] avec poids [{3}]
 upgradeHandler.connectionError=Erreur de la connection
 upgradeHandler.fallToDebug=\n\
 \ Note: les occurrences suivantes d'erreurs de stream HTTP/2 seront enregistrées au niveau DEBUG.
@@ -143,7 +142,6 @@ upgradeHandler.prefaceReceived=Connection [{0}], préface de la connection recue
 upgradeHandler.pruneIncomplete=Connexion [{0}], Flux [{1}], Erreur lors de l''élimination complète de la connexion parce que des flux sont encore actifs / utilisés dans l''arbre de priorité, il y a [{2}] flux en trop
 upgradeHandler.pruneStart=Connection [{0}] Début de l''élimination des anciens flux, la limite est de [{1}] et il y a actuellement [{2}] flux
 upgradeHandler.pruned=Connection [{0}] Elimination du flux terminé [{1}]
-upgradeHandler.prunedPriority=La connexion [{0}] a élagué le flux inutilisé [{1}] qui faisait peut-être partie de l''arbre de priorité
 upgradeHandler.releaseBacklog=Connection [{0}], Flux [{1}] enlevée de la file d''attente
 upgradeHandler.reset.receive=Connection [{0}], Stream [{1}], Reset a été reçu à cause de [{2}]
 upgradeHandler.rst.debug=Connexion [{0}], Flux [{1}], Erreur [{2}], Message [{3}], RST (fermeture du flux)
diff --git a/java/org/apache/coyote/http2/LocalStrings_ja.properties b/java/org/apache/coyote/http2/LocalStrings_ja.properties
index b0e237d260..a9b7b8b59d 100644
--- a/java/org/apache/coyote/http2/LocalStrings_ja.properties
+++ b/java/org/apache/coyote/http2/LocalStrings_ja.properties
@@ -126,7 +126,6 @@ streamStateMachine.invalidFrame=コネクション [{0}]、ストリーム [{1}]
 
 upgradeHandler.allocate.debug=コネクション [{0}]、ストリーム [{1}]、割り当てられた [{2}] バイト
 upgradeHandler.allocate.left=コネクション [{0}]、ストリーム [{1}]、[{2}] バイトが未割り当て - 子への割り当てを試みています
-upgradeHandler.allocate.recipient=コネクション [{0}]、ストリーム [{1}]、重み [{3}] の潜在的な受信者 [{2}]
 upgradeHandler.connectionError=接続エラー
 upgradeHandler.fallToDebug=注: HTTP/2 ストリームのエラーがさらに発生すると、DEBUG レベルでログに記録されます。
 upgradeHandler.goaway.debug=コネクション [{0}]、Goaway、最終ストリーム [{1}]、エラーコード [{2}]、デバッグデータ [{3}]
@@ -142,7 +141,6 @@ upgradeHandler.prefaceReceived=コネクション [{0}]、クライアントか
 upgradeHandler.pruneIncomplete=コネクション [{0}]、ストリーム [{1}]、コネクションを削除できませんでした。アクティブなストリーム数 [{2}] は多すぎます。
 upgradeHandler.pruneStart=コネクション [{0}] 古いストリームのプルーニングを開始します。 上限は [{1}]  で、現在 [{2}] ストリームがあります。
 upgradeHandler.pruned=コネクション [{0}]、完了したストリーム [{1}] は削除します。
-upgradeHandler.prunedPriority=コネクション [{0}]、優先度木に登録されていた可能性のある未使用のストリーム [{1}] を取り除きました。
 upgradeHandler.releaseBacklog=コネクション [{0}]、ストリーム [{1}] はバックログから解放されました
 upgradeHandler.reset.receive=Connection[{0}]、Stream[{1}]、[{2}]のためにリセットを受信しました
 upgradeHandler.rst.debug=コネクション [{0}]、ストリーム [{1}]、エラー [{2}]、メッセージ [{3}]、RST (ストリームを切断します)
diff --git a/java/org/apache/coyote/http2/LocalStrings_ko.properties b/java/org/apache/coyote/http2/LocalStrings_ko.properties
index e8b1825382..a8adb1f976 100644
--- a/java/org/apache/coyote/http2/LocalStrings_ko.properties
+++ b/java/org/apache/coyote/http2/LocalStrings_ko.properties
@@ -125,7 +125,6 @@ streamStateMachine.invalidFrame=연결 [{0}], 스트림 [{1}], 상태 [{2}], 프
 
 upgradeHandler.allocate.debug=연결 [{0}], 스트림 [{1}], [{2}] 바이트를 할당함.
 upgradeHandler.allocate.left=연결 [{0}], 스트림 [{1}], [{2}] 바이트들이 할당 해제되었습니다 - 자식들에 할당하려 시도합니다.
-upgradeHandler.allocate.recipient=연결 [{0}], 스트림 [{1}], 가중치 [{3}]의 잠재적 수신자 [{2}]
 upgradeHandler.connectionError=연결 오류
 upgradeHandler.goaway.debug=연결 [{0}], Goaway, 마지막 스트림 [{1}], 오류 코드 [{2}], 디버그 데이터 [{3}]
 upgradeHandler.init=연결 [{0}], 상태 [{1}]
@@ -140,7 +139,6 @@ upgradeHandler.prefaceReceived=연결 [{0}]: 연결 preface를 클라이언트
 upgradeHandler.pruneIncomplete=연결 [{0}]: 스트림들이 Priority tree에서 활성화되어 있거나 사용되고 있기 때문에, 해당 연결을 완전히 제거하지 못했습니다. 너무 많은 스트림들이 존재합니다: [{2}].
 upgradeHandler.pruneStart=연결 [{0}]: 이전 스트림들에 대한 가지치기를 시작합니다. 한계값은 [{1}] 이고, 현재 [{2}]개의 스트림들이 존재합니다.
 upgradeHandler.pruned=연결 [{0}]이(가) 완료된 스트림 [{1}]을(를) 제거했습니다.
-upgradeHandler.prunedPriority=연결 [{0}]이(가) 사용되지 않는 스트림 [{1}]을(를) 제거합니다. 해당 스트림은 priority tree의 일부였을 수 있습니다.
 upgradeHandler.releaseBacklog=연결 [{0}], 스트림 [{1}]이(가) 백로그로부터 해제되었습니다.
 upgradeHandler.reset.receive=연결 [{0}], 스트림 [{1}], [{2}](으)로 인해 리셋을 수신했습니다.
 upgradeHandler.rst.debug=연결 [{0}], 스트림 [{1}], 오류 [{2}], 메시지 [{3}],  RST (스트림을 닫습니다)
diff --git a/java/org/apache/coyote/http2/LocalStrings_zh_CN.properties b/java/org/apache/coyote/http2/LocalStrings_zh_CN.properties
index d0713e931a..ec4c7612ba 100644
--- a/java/org/apache/coyote/http2/LocalStrings_zh_CN.properties
+++ b/java/org/apache/coyote/http2/LocalStrings_zh_CN.properties
@@ -126,7 +126,6 @@ streamStateMachine.invalidFrame=连接{0}、流{1}、状态{2}、帧类型{3}
 
 upgradeHandler.allocate.debug=连接[{0}],流[{1}],已分配[{2}]字节
 upgradeHandler.allocate.left=连接[{0}],流[{1}],[{2}]字节未分配 - 尝试分配给子项
-upgradeHandler.allocate.recipient=(:连接[{0}],流[{1}],潜在接收者[{2}],权重为[{3}]
 upgradeHandler.connectionError=连接错误
 upgradeHandler.goaway.debug=连接[{0}],离开,最后的流[{1}],错误码[{2}],调试数据[{3}]
 upgradeHandler.init=连接[{0}],状态[{1}]
@@ -141,7 +140,6 @@ upgradeHandler.prefaceReceived=连接[{0}],从客户端收到连接准备。
 upgradeHandler.pruneIncomplete=连接[{0}],流[{1}],无法完全修剪连接,因为有[{2}]个活动流太多
 upgradeHandler.pruneStart=连接[{0}]正在开始修剪旧流。限制为[{1}],当前有[{2}]个流。
 upgradeHandler.pruned=连接[{0}]已修剪完成的流[{1}]
-upgradeHandler.prunedPriority=连接[{0}]已经成为了属于优先级树中未使用的流[{1}]
 upgradeHandler.releaseBacklog=连接[{0}],流[{1}]已从待办事项列表中释放
 upgradeHandler.reset.receive=连接[{0}],流[{1}],由于[{2}]而重置
 upgradeHandler.rst.debug=连接[{0}],流[{1}],错误[{2}],消息[{3}],RST(关闭流)
diff --git a/java/org/apache/coyote/http2/Stream.java b/java/org/apache/coyote/http2/Stream.java
index 53850fc384..f255029993 100644
--- a/java/org/apache/coyote/http2/Stream.java
+++ b/java/org/apache/coyote/http2/Stream.java
@@ -95,6 +95,9 @@ class Stream extends AbstractNonZeroStream implements HeaderEmitter {
     private Object pendingWindowUpdateForStreamLock = new Object();
     private int pendingWindowUpdateForStream = 0;
 
+    private volatile int urgency = Constants.DEFAULT_URGENCY;
+    private volatile boolean incremental = Constants.DEFAULT_INCREMENTAL;
+
 
     Stream(Integer identifier, Http2UpgradeHandler handler) {
         this(identifier, handler, null);
@@ -104,7 +107,6 @@ class Stream extends AbstractNonZeroStream implements HeaderEmitter {
     Stream(Integer identifier, Http2UpgradeHandler handler, Request coyoteRequest) {
         super(handler.getConnectionId(), identifier);
         this.handler = handler;
-        handler.addChild(this);
         setWindowSize(handler.getRemoteSettings().getInitialWindowSize());
         if (coyoteRequest == null) {
             // HTTP/2 new request
@@ -833,6 +835,26 @@ class Stream extends AbstractNonZeroStream implements HeaderEmitter {
     }
 
 
+    public int getUrgency() {
+        return urgency;
+    }
+
+
+    public void setUrgency(int urgency) {
+        this.urgency = urgency;
+    }
+
+
+    public boolean getIncremental() {
+        return incremental;
+    }
+
+
+    public void setIncremental(boolean incremental) {
+        this.incremental = incremental;
+    }
+
+
     class StreamOutputBuffer implements HttpOutputBuffer, WriteBuffer.Sink {
 
         private final ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org