2

在 HTTP/3 QPACK 中有一条指令用于复制动态表中的现有条目;据说它用于避免添加对旧条目的引用,这可能会阻止插入新条目。

但是,我看不出这有什么帮助。

如果动态表没有足够的空间容纳新条目而不驱逐其他条目,并且将被驱逐的条目是不可驱逐的,则编码器不得将该条目插入到动态表中(包括现有条目的副本)。

为了确保不阻止编码器添加新条目,编码器可以避免引用接近驱逐的条目。编码器可以发出重复指令(第 4.3.4 节),而不是引用这样的条目,而是引用重复项。

   +--------+---------------------------------+----------+
   | Unused |          Referenceable          | Draining |
   | Space  |             Entries             | Entries  |
   +--------+---------------------------------+----------+
            ^                                 ^          ^
            |                                 |          |
      Insertion Point                 Draining Index  Dropping
                                                       Point

(取自 IETF-QUIC-QPACK-DRAFT16)

这里的想法是,一旦一个字段通过了耗尽索引,我们想让它的存在优先级较低,所以我们会添加一个对它的引用,让任何新的请求都引用该引用,这样旧的字段就变得不被引用了它会被删除吗?在它被删除和添加新引用之间,那些中间请求可以填充到动态表中,否则会被阻塞?

谢谢你。

4

1 回答 1

2

旧条目的复制会生成该表条目的新副本;它不引用旧条目。这允许旧条目老化(被驱逐)。

复制指令实现了三个目标:

  1. 它允许驱逐旧条目(如上所述)。
  2. 它允许连续使用动态表,而不是再次插入新条目(旧条目的副本)并可能冒着阻塞听众的风险;和
  3. 从通过网络发送所需的字节数的角度来看,复制旧条目比插入新条目更便宜;这提高了压缩性能。

QPACK 互联网草案涉及在发出重复指令时可能是有利可图的。选择何时以及是否发出 Duplicate 指令是一个重要的决定,它可能会极大地影响压缩性能。每个编码器都会选择自己的策略。

例如,ls-qpack包含以下代码

    candidate = NULL;
    STAILQ_FOREACH(entry, &enc->qpe_all_entries, ete_next_all)
    {
        if (!qenc_entry_is_draining(enc, entry))
            break;
        if (candidate && ETE_SIZE(entry) < ETE_SIZE(candidate))
            continue;
        for (next = STAILQ_NEXT(entry, ete_next_nameval); next;
                                    next = STAILQ_NEXT(next, ete_next_nameval))
            if (next->ete_nameval_hash == entry->ete_nameval_hash
                    && next->ete_name_len == entry->ete_name_len
                    && next->ete_val_len == entry->ete_val_len
                    && 0 == memcmp(ETE_NAME(next), ETE_NAME(entry),
                                                        next->ete_name_len)
                    && 0 == memcmp(ETE_VALUE(next), ETE_VALUE(entry),
                                                        next->ete_val_len))
                break;
        if (!next
                && qenc_hist_seen(enc, HE_NAMEVAL, entry->ete_nameval_hash)
                        && qenc_has_or_can_evict_at_least(enc, ETE_SIZE(entry)))
            candidate = entry;
    }

代码说:找到一个尚未复制的耗尽条目,其名称和值最近已被使用(qenc_hist_seen()),并且可以复制(qenc_has_or_can_evict_at_least())。

于 2020-08-10T16:18:15.243 回答