Internet DRAFT - draft-tikhonov-quic-qmin

draft-tikhonov-quic-qmin







QUIC Working Group                                           D. Tikhonov
Internet-Draft                                    LiteSpeed Technologies
Intended status: Standards Track                       November 13, 2017
Expires: May 17, 2018


                   QMIN: Header Compression for QUIC
                      draft-tikhonov-quic-qmin-00

Abstract

   This specification defines QMIN, a compression format and protocol
   for HTTP/2 ([RFC7540]) headers.  QMIN is based on HPACK ([RFC7541]).
   The modifications to HPACK are meant to allow robust compression use
   in QUIC: That is, no head-of-line blocking and low overhead.  QMIN is
   guided by HPACK design principles.  It inherits all of HPACK's data
   structures and retains binary compatibility with it.  While designed
   with QUIC in mind, QMIN can be used in other contexts.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on May 17, 2018.

Copyright Notice

   Copyright (c) 2017 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents
   (https://trustee.ietf.org/license-info) in effect on the date of
   publication of this document.  Please review these documents
   carefully, as they describe your rights and restrictions with respect
   to this document.  Code Components extracted from this document must
   include Simplified BSD License text as described in Section 4.e of



Tikhonov                  Expires May 17, 2018                  [Page 1]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   the Trust Legal Provisions and are provided without warranty as
   described in the Simplified BSD License.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
   2.  Overview  . . . . . . . . . . . . . . . . . . . . . . . . . .   3
   3.  Checkpoint States . . . . . . . . . . . . . . . . . . . . . .   5
     3.1.  Checkpoint State: NEW . . . . . . . . . . . . . . . . . .   5
     3.2.  Checkpoint State: PENDING . . . . . . . . . . . . . . . .   5
     3.3.  Checkpoint State: LIVE  . . . . . . . . . . . . . . . . .   5
     3.4.  Checkpoint State: DEAD  . . . . . . . . . . . . . . . . .   6
   4.  Control Stream  . . . . . . . . . . . . . . . . . . . . . . .   6
     4.1.  Encoder Commands  . . . . . . . . . . . . . . . . . . . .   6
       4.1.1.  INSERT_ENTRY  . . . . . . . . . . . . . . . . . . . .   6
       4.1.2.  REUSE_ENTRY . . . . . . . . . . . . . . . . . . . . .   7
       4.1.3.  FLUSH_CHKPOINT  . . . . . . . . . . . . . . . . . . .   8
       4.1.4.  DROP_CHKPOINT . . . . . . . . . . . . . . . . . . . .   8
     4.2.  Decoder Messages  . . . . . . . . . . . . . . . . . . . .   9
       4.2.1.  ACK_FLUSH . . . . . . . . . . . . . . . . . . . . . .   9
     4.3.  Stream Notification Commands  . . . . . . . . . . . . . .   9
       4.3.1.  STREAM_DONE . . . . . . . . . . . . . . . . . . . . .   9
     4.4.  Expansion . . . . . . . . . . . . . . . . . . . . . . . .  10
   5.  Header Encoding . . . . . . . . . . . . . . . . . . . . . . .  10
   6.  Table Size Calculation  . . . . . . . . . . . . . . . . . . .  10
     6.1.  Entry Size  . . . . . . . . . . . . . . . . . . . . . . .  10
     6.2.  Checkpoint Size . . . . . . . . . . . . . . . . . . . . .  10
     6.3.  Overall Table Size  . . . . . . . . . . . . . . . . . . .  11
     6.4.  Comparison with HPACK . . . . . . . . . . . . . . . . . .  11
   7.  Encoding Process  . . . . . . . . . . . . . . . . . . . . . .  11
     7.1.  Indexable Header Fields . . . . . . . . . . . . . . . . .  11
       7.1.1.  New Index . . . . . . . . . . . . . . . . . . . . . .  11
       7.1.2.  Existing Index  . . . . . . . . . . . . . . . . . . .  11
     7.2.  Non-indexable Header Fields . . . . . . . . . . . . . . .  12
     7.3.  When Maximum Table Size Is Reached  . . . . . . . . . . .  12
     7.4.  Memory Cost of Flushing . . . . . . . . . . . . . . . . .  12
   8.  Decoding Process  . . . . . . . . . . . . . . . . . . . . . .  12
   9.  Encoder Strategies  . . . . . . . . . . . . . . . . . . . . .  13
     9.1.  Flushing and Dropping . . . . . . . . . . . . . . . . . .  13
       9.1.1.  Simple Strategy . . . . . . . . . . . . . . . . . . .  13
       9.1.2.  Rule-Based Strategy . . . . . . . . . . . . . . . . .  13
       9.1.3.  Feedback-Based Strategy . . . . . . . . . . . . . . .  14
     9.2.  Control Channel Cost  . . . . . . . . . . . . . . . . . .  14
   10. HPACK Interoperability  . . . . . . . . . . . . . . . . . . .  15
   11. Implementation Notes  . . . . . . . . . . . . . . . . . . . .  15
     11.1.  Control Messages Made Easy . . . . . . . . . . . . . . .  15
   12. QMIN Drawbacks  . . . . . . . . . . . . . . . . . . . . . . .  15
   13. Acknowledgements  . . . . . . . . . . . . . . . . . . . . . .  16



Tikhonov                  Expires May 17, 2018                  [Page 2]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   14. References  . . . . . . . . . . . . . . . . . . . . . . . . .  16
     14.1.  Normative References . . . . . . . . . . . . . . . . . .  16
     14.2.  Informative References . . . . . . . . . . . . . . . . .  16
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  16

1.  Introduction

   Google QUIC implementation uses HPACK to compress HTTP headers.  HTTP
   headers for all requests and responses are sent on a dedicated
   stream.  This introduces head-of-line (HoL) blocking: if this stream
   is blocked due to packet loss, all HTTP messages whose compressed
   headers follow the lost packet in the stream are stalled.  Solving
   the HoL problem has been one of the goals of the IETF QUIC Working
   Group.

   QMIN solves the HoL problem and has the following beneficial
   properties:

   o  The compression logic is mostly contained in the encoder, keeping
      the decoder simple.
   o  QMIN is transport-independent.
   o  Memory penalty over HPACK is manageable (Section 6.4).
   o  QMIN and HPACK are interoperable (Section 10).

2.  Overview

   The QMIN innovation is in using a *checkpointed* dynamic table, with
   the encoder always aware whether the decoder possesses the dynamic
   table entry (from here on, simply "entry") necessary for decoding a
   header.  The encoder learns this information from messages carried on
   a single dedicated control stream.  The reliable nature of this
   stream guarantees serialized protocol operation.

   In request and response streams, header blocks use either literal
   representations or references to entries that are known to exist in
   the decoder table.  Dynamic table changes are communicated via the
   control stream.  The process of decoding header blocks does not
   change the decoder state, thus avoiding the HoL blocking.

   QMIN inherits HPACK's data structures and encoding formats (see
   [RFC7541]).

   In addition, *checkpoints* are introduced.  A checkpoint is used to
   track entries added to the dynamic table and streams that reference
   those entries.

   Checkpoints are ordered in a list, from newest to oldest.  A new
   checkpoint gets appended to the "new" end of the checkpoint list.



Tikhonov                  Expires May 17, 2018                  [Page 3]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   The encoder always has a checkpoint in the NEW state.  Flushing a
   checkpoint is a two-step operation.  First, a FLUSH_CHKPOINT command
   is sent to the decoder.  At that time, the encoder's NEW checkpoint
   becomes PENDING.  The decoder moves its NEW checkpoint directly to
   LIVE and responds with ACK_FLUSH message.  When the encoder receives
   this message, its PENDING checkpoint becomes LIVE and entries
   associated with this checkpoint become available for encoding.

   The encoder always has exactly one NEW checkpoint, zero or one
   PENDING checkpoints, and zero or more LIVE and DEAD checkpoints.  The
   decoder has exactly one NEW checkpoint and zero or more LIVE
   checkpoints.

   Unused entries are evicted indirectly, by dropping checkpoints.
   Before a checkpoint can be dropped, its state is changed to DEAD: the
   encoder cannot use an entry for encoding that is not referenced by a
   LIVE checkpoint.  Changing a checkpoint's state to DEAD allows the
   checkpoint to age out.  The encoder can decide to drop a DEAD
   checkpoint when it is no longer referenced by any active streams.
   See Section 3.

   The control stream is used to notify the encoder that the peer is
   done decoding HTTP headers for a stream using the STREAM_DONE
   message.  The encoder uses this information to track which
   checkpoints can be dropped.

   When a checkpoint is dropped, the table entries it references are
   checked: if an entry is no longer referenced by any checkpoint, the
   entry is evicted.  The encoder sends the DROP_CHKPOINT command to the
   decoder when it drops a checkpoint; no acknowledgement for this
   command is necessary.

   Dropping a checkpoint and the entries associated with it is not
   limited to just the oldest checkpoint; any DEAD checkpoint -- as long
   as state transition rules are followed -- may be dropped.  This
   flexibility permits the encoder to use a number of strategies for
   entry eviction.

   As long as the maximum dynamic table size is observed, new
   checkpoints can be created; no upper limit on the number of
   checkpoints is specified.  A well-balanced spread of checkpoints
   permits the encoder to recycle entries effectively.

   The HPACK index address space stays the same.  The static table stays
   as-is.  Indices are unique between all checkpoints.  An index can be
   reused once no checkpoint references it.





Tikhonov                  Expires May 17, 2018                  [Page 4]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


3.  Checkpoint States

   A checkpoint can be in one of several states.  It goes through these
   states in order, without skipping any, throughout its lifetime.

   On the encoder, the checkpoint states are:

   o  NEW
   o  PENDING
   o  LIVE
   o  DEAD

   On the decoder, only two states are used:

   o  NEW
   o  LIVE

3.1.  Checkpoint State: NEW

   Applicability: encoder and decoder.

   All newly reused or inserted entries are referred to by the NEW
   checkpoint.  There is always a NEW checkpoint.  Whenever this
   checkpoint changes state, a new NEW checkpoint is created.

   The encoder and the decoder both begin with an empty NEW checkpoint.

3.2.  Checkpoint State: PENDING

   Applicability: encoder only.

   At some point, the encoder may want to flush new entries.  It then
   changes the NEW checkpoint state to PENDING and issues the
   FLUSH_CHKPOINT command.  The entries in the PENDING checkpoint cannot
   be used for encoding yet; the encoder waits for ACK_FLUSH message.
   Upon receipt of this message, the PENDING checkpoint changes to the
   LIVE state.

   There can be at most one PENDING checkpoint.

3.3.  Checkpoint State: LIVE

   Applicability: encoder and decoder.

   Entries that were added to the dynamic table when this checkpoint was
   in the NEW state can now be used to encode and decode headers.  The
   decoder moves its NEW checkpoint to LIVE when it receives the




Tikhonov                  Expires May 17, 2018                  [Page 5]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   FLUSH_CHKPOINT command.  The encoder moves its PENDING checkpoint to
   LIVE when it receives the ACK_FLUSH message.

   Other than the maximum table size, the number of LIVE checkpoints is
   not limited.

3.4.  Checkpoint State: DEAD

   Applicability: encoder only.

   To evict old entries, the encoder marks a LIVE checkpoint as DEAD.
   (An entry that is not referenced by any LIVE checkpoint cannot be
   used for header encoding.  Marking a checkpoint DEAD allows entries
   to age out.)  When all streams whose header blocks were encoded using
   entries referenced by this checkpoint have been closed, the
   checkpoint is destroyed and the DROP_CHKPOINT message is sent to the
   decoder.

   There can be any number of DEAD checkpoints.

4.  Control Stream

   The control stream is used to carry messages to the encoder and the
   decoder.  This is the only way that dynamic table changes are
   communicated to the decoder.

   The messages are either

   o  Commands issued by the encoder to the decoder;
   o  Acknowledgements issued by the decoder; or
   o  Stream processed notifications sent to the encoder.

   The format of the messages is similar in structure to the format of
   the encoded header fields in the header block as specified in HPACK
   (RFC 7541, Section 6).  The same variable-length integer encoding
   mechanism is used (RFC 7541, Section 5).

4.1.  Encoder Commands

   The encoder issues the following commands:

4.1.1.  INSERT_ENTRY

   This message is sent by the encoder at the same time it creates a new
   indexed entry in its dynamic table.  The smallest unused index in the
   address space ( [62 - oO] ) MUST be assigned to the new entry.





Tikhonov                  Expires May 17, 2018                  [Page 6]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   The decoder creates the new entry in the table, but does not make the
   entry available for decoding yet.  If indexed name representation is
   used, but the decoder does not have this entry already referenced by
   its NEW checkpoint, it MUST treat it as an error.

   The format of this message is identical to HPACK's Literal Header
   Field Representation (RFC 7541, Section 6.2).

        0   1   2   3   4   5   6   7
      +---+---+---+---+---+---+---+---+
      | 0 | 1 |      Index (6+)       |
      +---+---+-----------------------+
      | H |     Value Length (7+)     |
      +---+---------------------------+
      | Value String (Length octets)  |
      +-------------------------------+

                       Figure: Insert Entry - Indexed Name

        0   1   2   3   4   5   6   7
      +---+---+---+---+---+---+---+---+
      | 0 | 1 |           0           |
      +---+---+-----------------------+
      | H |     Name Length (7+)      |
      +---+---------------------------+
      |  Name String (Length octets)  |
      +---+---------------------------+
      | H |     Value Length (7+)     |
      +---+---------------------------+
      | Value String (Length octets)  |
      +-------------------------------+

                       Figure: Insert Entry - New Name

4.1.2.  REUSE_ENTRY

   This message is issued instead of INSERT_ENTRY whenever the encoder
   uses an indexed representation from an existing LIVE checkpoint to
   encode a header and this index has not yet been added to the NEW
   checkpoint.

   Upon receipt of the REUSE_ENTRY command, the decoder creates a
   reference to the corresponding entry in its NEW checkpoint.

   The encoder MUST NOT issue multiple REUSE_ENTRY commands for the same
   entry in the context of the same NEW checkpoint.  If the decoder
   receives the REUSE_ENTRY message that specifies an index already
   referenced by its NEW checkpoint, it MUST treat it as an error.  If a



Tikhonov                  Expires May 17, 2018                  [Page 7]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   non-existent index is specified, the decoder MUST treat is as an
   error.

   The format of this message is identical to HPACK's Indexed Header
   Field Representation (RFC 7541, Section 6.1).

        0   1   2   3   4   5   6   7
      +---+---+---+---+---+---+---+---+
      | 1 |        Index (7+)         |
      +---+---------------------------+

                       Figure: Reuse Entry Message

4.1.3.  FLUSH_CHKPOINT

   When the encoder wants to start using entries associated with the NEW
   checkpoint, it moves it from NEW to PENDING state and issues the
   FLUSH_CHKPOINT command.

   The decoder moves its checkpoint from NEW to LIVE: all newly inserted
   entries become available for decoding.

        0   1   2   3   4   5   6   7
      +---+---+---+---+---+---+---+---+
      | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
      +---+---------------------------+

                       Figure: Flush Checkpoint

4.1.4.  DROP_CHKPOINT

   When a DEAD checkpoint is no longer referenced by any streams, the
   encoder MAY drop it.  This means evicting all dynamic table entries
   whose reference counts have gone to zero and issuing the
   DROP_CHKPOINT command.

   The ID of the checkpoint to drop is its current position in the
   checkpoint list, from oldest to newest.  Thus, the oldest checkpoint
   has ID 0, second-oldest has ID 1, and so on.

   The decoder performs the same operation as the encoder: decrements
   reference counts of dynamic table entries -- evicting those whose
   reference counts are now zero -- and drops the specified checkpoint.








Tikhonov                  Expires May 17, 2018                  [Page 8]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


        0   1   2   3   4   5    6    7
      +---+---+---+---+---+---+----+----+
      | 0 | 0 | 0 | 0 | 0 | 1 | ID (2+) |
      +---+------------------------+----+

                       Figure: Drop Checkpoint

4.2.  Decoder Messages

   The decoder sends replies to one of the encoder commands.

4.2.1.  ACK_FLUSH

   The decoder SHOULD inform the encoder that it has performed the flush
   using ACK_FLUSH message.  The encoder's PENDING checkpoint becomes
   LIVE when this acknowledgement is received.

        0   1   2   3   4   5   6   7
      +---+---+---+---+---+---+---+---+
      | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
      +---+---------------------------+

                       Figure: Ack Flush

4.3.  Stream Notification Commands

4.3.1.  STREAM_DONE

   When all HTTP headers for a stream have been decoded, this message is
   sent to inform the encoder that the peer is done with the stream.
   This allows the encoder to decrement its reference counts,
   potentially triggering a checkpoint flush or a checkpoint drop.

   It is preferable to send this message as soon as possible.  For
   example, one does not have to wait until stream FIN is read if HTTP
   headers have been decoded and there are no trailers.

        0   1   2   3   4   5    6    7
      +---+---+---+---+---+----+-----+-----+
      | 0 | 0 | 0 | 0 | 1 | Stream ID (3+) |
      +---+--------------------------------+

                       Figure: Stream Done

   The client knows that the server is done with the request if the
   stream is reset or it has read all of the response.  A QMIN
   implementation SHOULD use this knowledge to let the encoder know that




Tikhonov                  Expires May 17, 2018                  [Page 9]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   the stream is done.  The encoder SHOULD use the earliest indicator to
   move its mechanisms along.  Any subsequent indicators are no-ops.

4.4.  Expansion

   Two bit patterns are still available to the command coding scheme:
   001 and 00000001.  The former is used to encode the dynamic table
   size update by HPACK (RFC 7541, Section 6.3).  There is no inherent
   limitation in QMIN as to why it could not support this command.

5.  Header Encoding

   The headers are encoded in the same way they are encoded by HPACK,
   except QMIN does not support the dynamic table size update specified
   in RFC 7541, Section 6.3 in the headers block.  This is because
   header block decoding is not to change the decoder state.

6.  Table Size Calculation

   HPACK defines the dynamic table size as "the sum of the size of its
   entries."  (RFC 7541, Section 4.1).  QMIN's dynamic table entry
   carries another element -- reference count -- which increases the
   entry size.

   QMIN introduces checkpoints, whose size should also be accounted for.
   A decoder-side checkpoint keeps track of the index values created or
   reused when it was NEW.

6.1.  Entry Size

   A QMIN entry contains a reference count, which makes it larger that
   the HPACK entry.  Using a standard integer size, the QMIN entry
   overhead is set to 36 bytes: 32 bytes overhead of the HPACK entry
   plus four bytes for the additional reference count field.  Thus, the
   QMIN entry size is the sum of the entry name size, the entry value
   size, and 36.

6.2.  Checkpoint Size

   QMIN uses the smallest possible available value (Section 4.1.2) in
   the index address space for new entries.  Therefore, the total number
   of index values is at most the value of the largest index in use.  A
   checkpoint can track indices via a bitmask: 1 bit per index.  The
   size of a checkpoint, then, is defined as

       (Highest Index Value - 62) / 8 + 128

   The additional 128 bytes is the checkpoint overhead.



Tikhonov                  Expires May 17, 2018                 [Page 10]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


6.3.  Overall Table Size

   The decoder table size is calculated as number of entries times the
   entry size as calculated in Section 6.1 plus the number of
   checkpoints times the checkpoint size as calculated in Section 6.2.

6.4.  Comparison with HPACK

   In HPACK, a table with 700 dynamic entries and 35,000 bytes allocated
   to header names and values is

       700 * 32 + 35,000 = 57,400 bytes.

   The same table in QMIN with 10 checkpoints is

       700 * 36 + 35,000 + 10 * ((1000 / 8) + 128) = 62,730 bytes.

   This is a 9% increase in memory consumption.

7.  Encoding Process

   Given a header field to compress, the encoder returns the compressed
   representation of it.  In addition, it may emit one or more commands
   that should be sent on the control stream.

7.1.  Indexable Header Fields

   An indexable header field is that which the user specifies as "with
   indexing" (RFC 7541, Section 6.2).

7.1.1.  New Index

   If no matching entry is found, a new entry is created, its ID is
   recorded in the NEW checkpoint, and the encoder emits the
   INSERT_ENTRY command.

   If the encoded name component refers to an existing entry, this entry
   is reused as described in Section 7.1.2.

7.1.2.  Existing Index

   An indexable header field causes the encoder to search the table.  If
   an existing dynamic table entry is found that is referenced by at
   least one LIVE checkpoint, it can be used to encode the header field.
   The encoder records a reference to the stream using this entry in one
   of the checkpoints.  (Which checkpoint to select can be decided based
   on strategy.  See Section 9.1).




Tikhonov                  Expires May 17, 2018                 [Page 11]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   If the NEW checkpoint does not have a reference to this entry, the
   reference is recorded in the NEW checkpoint and the REUSE_ENTRY
   command is emitted.

7.2.  Non-indexable Header Fields

   Non-indexable header fields are compressed the same way as HPACK (RFC
   7541, Sections 6.2.2 and 6.2.3).  The encoder state is not changed.
   No command is emitted.

7.3.  When Maximum Table Size Is Reached

   When the encoder table reaches its maximum size, further insertions
   into the dynamic table are not possible.  In this case, the encoder
   compresses header fields without inserting or reusing entries and
   without emitting any commands.

   A simple recovery strategy is to mark one or more checkpoints DEAD
   immediately.

   Alternatively, the existing table may provide an acceptable
   compression level.  It may be more efficient to wait until this level
   falls below a threshold before marking checkpoints DEAD, as it may
   become possible to drop an already-DEAD checkpoint before the
   threshold is reached.

   The encoder SHOULD try to avoid reaching a point when it can no
   longer insert new entries.  See Section 9.

7.4.  Memory Cost of Flushing

   Because flushing automatically creates a new NEW checkpoint, it is
   possible to get into a situation where a flush is not possible due to
   the memory constraint.  If inserting a new entry would result in
   subsequent inability to flush, the encoder SHOULD flush instead.

8.  Decoding Process

   All header field representations defined in HPACK (Section 6 of
   [RFC7541]) are used as-is.  Dynamic size update (Ibid., Section 6.3)
   or an unknown command MUST be treated as an error.

   The decoder looks up dynamic entries in its table when it is given a
   header list to decode.  If corresponding entry is not found or if it
   is found but not referred to by any of LIVE checkpoints, this MUST be
   treated as an error.





Tikhonov                  Expires May 17, 2018                 [Page 12]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


9.  Encoder Strategies

9.1.  Flushing and Dropping

   The encoder decides when to flush checkpoints and when to declare
   them dead.  Flushing SHOULD occur when enough new entries have been
   created to try to reuse them.  Marking checkpoints as DEAD SHOULD
   happen before the table size is exhausted.

   If an entry used to encode a header field is referenced to by more
   than one LIVE checkpoint, one of them is selected to refer to the
   stream ID whose header field has been encoded.  Which LIVE checkpoint
   to pick is a decision that also affects compression performance.

   Several strategies are outlined below.

9.1.1.  Simple Strategy

   The encoder picks a number of streams to use as a threshold for
   flushing checkpoints.  Every time header blocks for N streams have
   been encoded, flush.

   The encoder picks the oldest checkpoint to mark as DEAD.  It does so
   when table size reaches some proportion, let's say 3/4, of the
   maximum table size.

   The newest LIVE checkpoint that references an entry used for encoding
   is picked to record the stream ID.

   This strategy is estimated to work well most of the time due to the
   temporal aspect of the checkpoint dropping policy.  When a connection
   is used to serve a small number of requests, however, the compression
   will be overall suboptimal, as the initial period when no dynamic
   table is available for encoding is amortized poorly.

9.1.2.  Rule-Based Strategy

   Heuristic rules may provide performance improvement over the simple
   strategy above.  For example:

   o  Flush very often, perhaps once for every new stream, when the
      number of dynamic entries is very small (such as when the encoder
      has just been instantiated).  Since the table size is likely to be
      small when only few dynamic entries exist, one can fit a lot of
      checkpoints and still be able to add new entries to the table.
      These early-flushed checkpoints will also be easier to drop later,
      as they are not referenced by many streams.




Tikhonov                  Expires May 17, 2018                 [Page 13]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   o  Flush when the number of newly added entries is 1/10 of the number
      of existing entries.  When this many new entries have been added,
      it is a likely indicator making them available for encoding will
      improve overall compression.
   o  When declaring a checkpoint DEAD:

      *  Pick a LIVE checkpoint that is referenced by the fewest
         existing streams; or
      *  Pick a LIVE checkpoint that references the largest number of
         old entries, where an "old" entry is that which has not been
         used for encoding in a period of some number of checkpoints.

   Other rules are possible.

9.1.3.  Feedback-Based Strategy

   The goal of QMIN is to produce the best compression.  The compression
   level can be computed by dividing the sum of the sizes of all header
   fields submitted for compression by the number of compressed bytes
   returned *plus* the size of all commands sent to the decoder.  A
   checkpoint can be taken as unit of time and a decaying average can be
   computed.

   Availability of entries that can be used for compression directly
   affects compression performance.  This availability, in turn, is a
   function of how often checkpoints are flushed and which checkpoints
   are marked for deletion.  Flushing very often costs memory;
   infrequent flushing delays entry availability.

   It is possible to come up with a dynamic function that adjusts these
   parameters based on feedback: the compression performance.

9.2.  Control Channel Cost

   Sending commands on the control channel affects the overall
   compression level.  Sending an INSERT_ENTRY command for a header
   field that is never reused is more expensive than not inserting the
   field at all.  A single large, ever-changing HTTP header (for
   example, session state in a cookie) could defeat the compression
   mechanism.  The encoder SHOULD prevent this from happening.

   Since a header field that repeats is likely to repeat more than once,
   a simple conservative approach is never to insert a header field that
   is not known to have repeated.  Because HTTP header names are
   relatively small and not as numerous as the header values, it is
   possible to maintain a history of a number of recently compressed
   header fields.  (To use less memory, hashes of header values, instead
   of the values themselves, can be stored.)  The encoder can consult



Tikhonov                  Expires May 17, 2018                 [Page 14]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


   this history and only issue an INSERT_ENTRY command if the header
   field has been seen before.

10.  HPACK Interoperability

   Because QMIN uses the same binary format as HPACK, the two are
   interoperable.  This makes it possible for peers to use the current
   HTTP/QUIC HPACK mechanism to talk to peers that use QMIN.  It is
   useful: all implementations do not have to start using QMIN at the
   same time.

   For this to work, four things must be true:

   1.  The HPACK side must advertise maximum dynamic table size of zero.
   2.  The HPACK side must not send dynamic table size updates.
   3.  The HPACK side must consume and discard data sent on the control
       stream.  This is so that QMIN sender does not get stuck when it
       reaches the stream flow control limit.
   4.  The HPACK side must assume that peer's dynamic table size is
       zero.  This is to prevent HPACK encoder from relying on dynamic
       entries.

   (1) and (2) are already true according to [I-D.ietf-quic-http].  (3)
   and (4) are trivial modifications.

11.  Implementation Notes

11.1.  Control Messages Made Easy

   Since INSERT_ENTRY and REUSE_ENTRY messages are identical to the
   encoded header field representation, the latter can be placed onto
   the control stream verbatim.  Generate once, use twice.

12.  QMIN Drawbacks

   The following QMIN properties affect compression negatively:

   o  All insertion commands are duplicated: they are sent both as
      literal representation in headers block and as insertion commands
      on the control stream.
   o  A new entry cannot be used until the checkpoint is flushed and the
      encoder receives ACK_FLUSH message.  Until that time, the header
      field literal representation must be used for subsequent
      encodings.







Tikhonov                  Expires May 17, 2018                 [Page 15]

Internet-Draft      QMIN: Header Compression for QUIC      November 2017


13.  Acknowledgements

   QMIN is based on HPACK ([RFC7540]); I am thankful to its authors.

   Observations of the following members of the IETF QUIC WG have been
   particularly insightful:

   o  Alan Frindell;
   o  Charles 'Buck' Krasic; and
   o  Mike Bishop.

   Finally, my colleagues at LiteSpeed Technologies reviewed the rough
   draft and provided valuable feedback:

   o  George Wang;
   o  Ron Saad.

14.  References

14.1.  Normative References

   [RFC7540]  Belshe, M., Peon, R., and M. Thomson, Ed., "Hypertext
              Transfer Protocol Version 2 (HTTP/2)", RFC 7540,
              DOI 10.17487/RFC7540, May 2015,
              <https://www.rfc-editor.org/info/rfc7540>.

   [RFC7541]  Peon, R. and H. Ruellan, "HPACK: Header Compression for
              HTTP/2", RFC 7541, DOI 10.17487/RFC7541, May 2015,
              <https://www.rfc-editor.org/info/rfc7541>.

14.2.  Informative References

   [I-D.ietf-quic-http]
              Bishop, M., "Hypertext Transfer Protocol (HTTP) over
              QUIC", draft-ietf-quic-http-07 (work in progress), October
              2017.

Author's Address

   Dmitri Tikhonov
   LiteSpeed Technologies

   Email: dtikhonov@litespeedtech.com








Tikhonov                  Expires May 17, 2018                 [Page 16]