Add minimal spdy priority set by gws response header for initial cwnd bootstrapping for http2. also store spdy priority within spdydispatcher::sessiondata. no production behavior change unless we start an additional gws experiment. protected by gfe2_restart_flag_h2_adjust_initial_cwnd_by_gws.

While QUIC stores SPDY within spdy::PriorityWriteScheduler<...>, SPDY priority is stored in a map from stream_id to SessionData owned by SpdyClientDispatcher in this change because
(1) H2 uses LIFOWriteScheduler<...> by default, which ignores precedence (http://shortn/_2Ny3X9xBh6).
(2) We only need CWND bootstrapping for traffic from client, and hence only SpdyClientDispatcher populates the SPDY priority.

PiperOrigin-RevId: 316117083
Change-Id: I232e421b16edecc5f7146ce4fb36592a71a7e86f
diff --git a/spdy/core/fifo_write_scheduler.h b/spdy/core/fifo_write_scheduler.h
index a2c6989..7b31891 100644
--- a/spdy/core/fifo_write_scheduler.h
+++ b/spdy/core/fifo_write_scheduler.h
@@ -29,6 +29,8 @@
                       const StreamPrecedenceType& precedence) override;
   void UnregisterStream(StreamIdType stream_id) override;
   bool StreamRegistered(StreamIdType stream_id) const override;
+  // Stream precedence is available but note that it is not used for scheduling
+  // in this scheduler.
   StreamPrecedenceType GetStreamPrecedence(
       StreamIdType stream_id) const override;
   void UpdateStreamPrecedence(StreamIdType stream_id,
@@ -51,20 +53,26 @@
   std::string DebugString() const override;
 
  private:
+  struct StreamInfo {
+    SpdyPriority priority;
+    int64_t event_time;  // read/write event time (us since Unix epoch).
+  };
+
   std::set<StreamIdType> ready_streams_;
-  // This map maps stream ID to read/write event time (us since Unix epoch).
-  std::map<StreamIdType, int64_t> registered_streams_;
+  std::map<StreamIdType, StreamInfo> registered_streams_;
 };
 
 template <typename StreamIdType>
 void FifoWriteScheduler<StreamIdType>::RegisterStream(
     StreamIdType stream_id,
-    const StreamPrecedenceType& /*precedence*/) {
+    const StreamPrecedenceType& precedence) {
   if (StreamRegistered(stream_id)) {
     SPDY_BUG << "Stream " << stream_id << " already registered";
     return;
   }
-  registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0);
+  registered_streams_.emplace_hint(
+      registered_streams_.end(), stream_id,
+      StreamInfo{/*priority=*/precedence.spdy3_priority(), /*event_time=*/0});
 }
 
 template <typename StreamIdType>
@@ -88,14 +96,26 @@
 template <typename StreamIdType>
 typename FifoWriteScheduler<StreamIdType>::StreamPrecedenceType
 FifoWriteScheduler<StreamIdType>::GetStreamPrecedence(
-    StreamIdType /*stream_id*/) const {
-  return StreamPrecedenceType(kV3LowestPriority);
+    StreamIdType stream_id) const {
+  auto it = registered_streams_.find(stream_id);
+  if (it == registered_streams_.end()) {
+    SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+    return StreamPrecedenceType(kV3LowestPriority);
+  }
+  return StreamPrecedenceType(it->second.priority);
 }
 
 template <typename StreamIdType>
 void FifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
-    StreamIdType /*stream_id*/,
-    const StreamPrecedenceType& /*precedence*/) {}
+    StreamIdType stream_id,
+    const StreamPrecedenceType& precedence) {
+  auto it = registered_streams_.find(stream_id);
+  if (it == registered_streams_.end()) {
+    SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+    return;
+  }
+  it->second.priority = precedence.spdy3_priority();
+}
 
 template <typename StreamIdType>
 std::vector<StreamIdType> FifoWriteScheduler<StreamIdType>::GetStreamChildren(
@@ -109,7 +129,7 @@
     int64_t now_in_usec) {
   auto it = registered_streams_.find(stream_id);
   if (it != registered_streams_.end()) {
-    it->second = now_in_usec;
+    it->second.event_time = now_in_usec;
   } else {
     SPDY_BUG << "Stream " << stream_id << " is not registered";
   }
@@ -128,7 +148,8 @@
     if (stream_id <= it->first) {
       break;
     }
-    latest_event_time_us = std::max(latest_event_time_us, it->second);
+    latest_event_time_us =
+        std::max(latest_event_time_us, it->second.event_time);
   }
   return latest_event_time_us;
 }
diff --git a/spdy/core/fifo_write_scheduler_test.cc b/spdy/core/fifo_write_scheduler_test.cc
index 950b641..d1dd066 100644
--- a/spdy/core/fifo_write_scheduler_test.cc
+++ b/spdy/core/fifo_write_scheduler_test.cc
@@ -80,6 +80,24 @@
   EXPECT_EQ(0, fifo.GetLatestEventWithPrecedence(1));
 }
 
+TEST(FifoWriteSchedulerTest, GetStreamPrecedence) {
+  FifoWriteScheduler<SpdyStreamId> fifo;
+  // Return lowest priority for unknown stream.
+  EXPECT_EQ(kV3LowestPriority, fifo.GetStreamPrecedence(1).spdy3_priority());
+
+  fifo.RegisterStream(1, SpdyStreamPrecedence(3));
+  EXPECT_TRUE(fifo.GetStreamPrecedence(1).is_spdy3_priority());
+  EXPECT_EQ(3, fifo.GetStreamPrecedence(1).spdy3_priority());
+
+  // Redundant registration shouldn't change stream priority.
+  EXPECT_SPDY_BUG(fifo.RegisterStream(1, SpdyStreamPrecedence(4)),
+                  "Stream 1 already registered");
+  EXPECT_EQ(3, fifo.GetStreamPrecedence(1).spdy3_priority());
+
+  fifo.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5));
+  EXPECT_EQ(5, fifo.GetStreamPrecedence(1).spdy3_priority());
+}
+
 }  // namespace test
 
 }  // namespace spdy
diff --git a/spdy/core/lifo_write_scheduler.h b/spdy/core/lifo_write_scheduler.h
index 405ccf5..d2e7fcf 100644
--- a/spdy/core/lifo_write_scheduler.h
+++ b/spdy/core/lifo_write_scheduler.h
@@ -5,6 +5,7 @@
 #ifndef QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_
 #define QUICHE_SPDY_CORE_LIFO_WRITE_SCHEDULER_H_
 
+#include <cstdint>
 #include <map>
 #include <set>
 #include <string>
@@ -40,15 +41,13 @@
     return registered_streams_.find(stream_id) != registered_streams_.end();
   }
 
-  // Stream precedence is not supported by this scheduler.
+  // Stream precedence is available but note that it is not used for scheduling
+  // in this scheduler.
   StreamPrecedenceType GetStreamPrecedence(
-      StreamIdType /*stream_id*/) const override {
-    return StreamPrecedenceType(kV3LowestPriority);
-  }
+      StreamIdType stream_id) const override;
 
-  void UpdateStreamPrecedence(
-      StreamIdType /*stream_id*/,
-      const StreamPrecedenceType& /*precedence*/) override {}
+  void UpdateStreamPrecedence(StreamIdType stream_id,
+                              const StreamPrecedenceType& precedence) override;
 
   std::vector<StreamIdType> GetStreamChildren(
       StreamIdType /*stream_id*/) const override {
@@ -85,19 +84,26 @@
  private:
   friend class test::LifoWriteSchedulerPeer<StreamIdType>;
 
+  struct StreamInfo {
+    SpdyPriority priority;
+    int64_t event_time;  // read/write event time (us since Unix epoch).
+  };
+
   std::set<StreamIdType> ready_streams_;
-  std::map<StreamIdType, int64_t> registered_streams_;
+  std::map<StreamIdType, StreamInfo> registered_streams_;
 };
 
 template <typename StreamIdType>
 void LifoWriteScheduler<StreamIdType>::RegisterStream(
     StreamIdType stream_id,
-    const StreamPrecedenceType& /*precedence*/) {
+    const StreamPrecedenceType& precedence) {
   if (StreamRegistered(stream_id)) {
     SPDY_BUG << "Stream " << stream_id << " already registered";
     return;
   }
-  registered_streams_.emplace_hint(registered_streams_.end(), stream_id, 0);
+  registered_streams_.emplace_hint(
+      registered_streams_.end(), stream_id,
+      StreamInfo{/*priority=*/precedence.spdy3_priority(), /*event_time=*/0});
 }
 
 template <typename StreamIdType>
@@ -112,12 +118,36 @@
 }
 
 template <typename StreamIdType>
+typename LifoWriteScheduler<StreamIdType>::StreamPrecedenceType
+LifoWriteScheduler<StreamIdType>::GetStreamPrecedence(
+    StreamIdType stream_id) const {
+  auto it = registered_streams_.find(stream_id);
+  if (it == registered_streams_.end()) {
+    SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+    return StreamPrecedenceType(kV3LowestPriority);
+  }
+  return StreamPrecedenceType(it->second.priority);
+}
+
+template <typename StreamIdType>
+void LifoWriteScheduler<StreamIdType>::UpdateStreamPrecedence(
+    StreamIdType stream_id,
+    const StreamPrecedenceType& precedence) {
+  auto it = registered_streams_.find(stream_id);
+  if (it == registered_streams_.end()) {
+    SPDY_DVLOG(1) << "Stream " << stream_id << " not registered";
+    return;
+  }
+  it->second.priority = precedence.spdy3_priority();
+}
+
+template <typename StreamIdType>
 void LifoWriteScheduler<StreamIdType>::RecordStreamEventTime(
     StreamIdType stream_id,
     int64_t now_in_usec) {
   auto it = registered_streams_.find(stream_id);
   if (it != registered_streams_.end()) {
-    it->second = now_in_usec;
+    it->second.event_time = now_in_usec;
   } else {
     SPDY_BUG << "Stream " << stream_id << " is not registered";
   }
@@ -134,8 +164,8 @@
   for (auto it = registered_streams_.rbegin(); it != registered_streams_.rend();
        ++it) {
     if (stream_id < it->first) {
-      if (it->second > latest_event_time_us) {
-        latest_event_time_us = it->second;
+      if (it->second.event_time > latest_event_time_us) {
+        latest_event_time_us = it->second.event_time;
       }
     } else {
       break;
diff --git a/spdy/core/lifo_write_scheduler_test.cc b/spdy/core/lifo_write_scheduler_test.cc
index 1d7ecbf..744ee13 100644
--- a/spdy/core/lifo_write_scheduler_test.cc
+++ b/spdy/core/lifo_write_scheduler_test.cc
@@ -151,6 +151,24 @@
                   "Stream 11 is not registered");
 }
 
+TEST(LifoWriteSchedulerTest, GetStreamPrecedence) {
+  LifoWriteScheduler<SpdyStreamId> lifo;
+  // Return lowest priority for unknown stream.
+  EXPECT_EQ(kV3LowestPriority, lifo.GetStreamPrecedence(1).spdy3_priority());
+
+  lifo.RegisterStream(1, SpdyStreamPrecedence(3));
+  EXPECT_TRUE(lifo.GetStreamPrecedence(1).is_spdy3_priority());
+  EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority());
+
+  // Redundant registration shouldn't change stream priority.
+  EXPECT_SPDY_BUG(lifo.RegisterStream(1, SpdyStreamPrecedence(4)),
+                  "Stream 1 already registered");
+  EXPECT_EQ(3, lifo.GetStreamPrecedence(1).spdy3_priority());
+
+  lifo.UpdateStreamPrecedence(1, SpdyStreamPrecedence(5));
+  EXPECT_EQ(5, lifo.GetStreamPrecedence(1).spdy3_priority());
+}
+
 }  // namespace test
 
 }  // namespace spdy