Author: rhuijben
Date: Fri Nov 20 00:44:20 2015
New Revision: 1715309
URL: http://svn.apache.org/viewvc?rev=1715309&view=rev
Log:
Extend the hpack encoder with the first bits of dynamic table compression.
* buckets/hpack_buckets.c
(hpack_int): Fix indentation.
(serialize): Find existing item we can reuse and use that to optimize
item encoding. Document that the dynamic table update is still
missing.
Modified:
serf/trunk/buckets/hpack_buckets.c
Modified: serf/trunk/buckets/hpack_buckets.c
URL:
http://svn.apache.org/viewvc/serf/trunk/buckets/hpack_buckets.c?rev=1715309&r1=1715308&r2=1715309&view=diff
==============================================================================
--- serf/trunk/buckets/hpack_buckets.c (original)
+++ serf/trunk/buckets/hpack_buckets.c Fri Nov 20 00:44:20 2015
@@ -777,10 +777,10 @@ void serf__bucket_hpack_do(serf_bucket_t
}
static void hpack_int(unsigned char flags,
- int bits,
- apr_uint32_t value,
- char to[6],
- apr_size_t *used)
+ int bits,
+ apr_uint32_t value,
+ char to[6],
+ apr_size_t *used)
{
unsigned char max_direct;
apr_size_t u;
@@ -813,13 +813,6 @@ static void hpack_int(unsigned char flag
static apr_status_t
serialize(serf_bucket_t *bucket)
{
- /* Quick and dirty write out headers for V2
-
- Needs A LOT of improvement.
-
- Currently implements a complete in memory copy to the least
- efficient HTTP2 / HPACK header format
- */
serf_hpack_context_t *ctx = bucket->data;
serf_bucket_alloc_t *alloc = bucket->allocator;
serf_hpack_table_t *tbl = ctx->tbl;
@@ -850,11 +843,15 @@ serialize(serf_bucket_t *bucket)
{
apr_status_t status;
apr_size_t len;
+ apr_uint32_t reuse = 0;
+ const serf_hpack_entry_t *e;
+ bool reuseVal = false;
+ apr_uint32_t i;
next = entry->next;
/* Make 100% sure the next entry will fit.
- ### Temporarily wastes ram
+ ### Using the actual size later on is far more memory efficient
*/
if (!buffer || (HPACK_ENTRY_SIZE(entry) > chunksize - offset))
{
@@ -871,74 +868,137 @@ serialize(serf_bucket_t *bucket)
offset = 0;
}
- /* Literal header, no indexing (=has a name) */
- hpack_int(0x40, 6, 0, buffer + offset, &len);
- offset += len;
+ for (i = 0; i < hpack_static_table_count; i++) {
+ e = &hpack_static_table[i];
- /* ### TODO: Check if we can refer key or key+value by index */
+ if (e->key_len == entry->key_len
+ && !memcmp(e->key, entry->key, e->key_len))
+ {
+ if (e->value_len == entry->value_len
+ && !memcmp(e->value, entry->value, e->value_len))
+ {
+ reuse = i+1;
+ reuseVal = true;
+ break;
+ }
+ if (!reuse)
+ reuse = i+1;
+ }
+ }
+ if (!reuseVal) {
+ for (e = tbl->lr_first; e; e = e->next) {
- /* To huff or not... */
- status = serf__hpack_huffman_encode(entry->key, entry->key_len,
- 0, NULL, &len);
- if (!status && len < entry->key_len)
- {
- apr_size_t int_len;
+ i++;
- /* It is more efficient to huffman encode */
- hpack_int(0x80, 7, len, buffer + offset, &int_len);
- offset += int_len;
+ if (e->key_len == entry->key_len
+ && !memcmp(e->key, entry->key, e->key_len))
+ {
+ if (e->value_len == entry->value_len
+ && !memcmp(e->value, entry->value, e->value_len))
+ {
+ reuse = i;
+ reuseVal = true;
+ break;
+ }
+ if (!reuse)
+ reuse = i;
+ }
+ }
+ }
- status = serf__hpack_huffman_encode(entry->key, entry->key_len,
- len,
- (void*)(buffer + offset),
- &len);
+ if (reuseVal) {
+ /* Nice, we have an exact match of key+value. We can
+ use those, but never index them. */
+ hpack_int(0x80, 7, reuse, buffer + offset, &len);
offset += len;
-
- if (status)
- return status;
}
- else
- {
- /* It is more efficient not to encode */
- hpack_int(0, 7, entry->key_len, buffer + offset, &len);
+ else if (!entry->dont_index) {
+ /* We reuse the header name, but will add our own value.
+ Or we don't reuse, but do index (value 0) */
+ hpack_int(0x40, 6, reuse, buffer + offset, &len);
+ offset += len;
+ }
+ else if (entry->dont_index == 2) {
+ /* Never index the value */
+ hpack_int(0x10, 4, reuse, buffer + offset, &len);
+ offset += len;
+ }
+ else {
+ hpack_int(0x00, 4, reuse, buffer + offset, &len);
offset += len;
-
- memcpy(buffer + offset, entry->key, entry->key_len);
- offset += entry->key_len;
}
- /* To huff or not... */
- status = serf__hpack_huffman_encode(entry->value, entry->value_len,
- 0, NULL, &len);
- if (!status && len < entry->key_len)
- {
- apr_size_t int_len;
+ if (!reuse) {
- /* It is more efficient to huffman encode */
- hpack_int(0x80, 7, len, buffer + offset, &int_len);
- offset += int_len;
-
- status = serf__hpack_huffman_encode(entry->value,
- entry->value_len,
- len,
- (void*)(buffer + offset),
- &len);
- offset += len;
+ /* To huff or not... */
+ status = serf__hpack_huffman_encode(entry->key, entry->key_len,
+ 0, NULL, &len);
+ if (!status && len < entry->key_len)
+ {
+ apr_size_t int_len;
+
+ /* It is more efficient to huffman encode */
+ hpack_int(0x80, 7, len, buffer + offset, &int_len);
+ offset += int_len;
+
+ status = serf__hpack_huffman_encode(entry->key, entry->key_len,
+ len,
+ (void*)(buffer + offset),
+ &len);
+ offset += len;
+
+ if (status)
+ return status;
+ }
+ else
+ {
+ /* It is more efficient not to encode */
+ hpack_int(0x00, 7, entry->key_len, buffer + offset, &len);
+ offset += len;
+
+ memcpy(buffer + offset, entry->key, entry->key_len);
+ offset += entry->key_len;
+ }
- if (status)
- return status;
}
- else
- {
- /* It is more efficient not to encode */
- hpack_int(0, 7, entry->value_len, buffer + offset, &len);
- offset += len;
+ if (!reuseVal) {
+ /* To huff or not... */
+ status = serf__hpack_huffman_encode(entry->value, entry->value_len,
+ 0, NULL, &len);
+ if (!status && len < entry->key_len)
+ {
+ apr_size_t int_len;
- memcpy(buffer + offset, entry->value, entry->value_len);
- offset += entry->value_len;
+ /* It is more efficient to huffman encode */
+ hpack_int(0x80, 7, len, buffer + offset, &int_len);
+ offset += int_len;
+
+ status = serf__hpack_huffman_encode(entry->value,
+ entry->value_len,
+ len,
+ (void*)(buffer + offset),
+ &len);
+ offset += len;
+
+ if (status)
+ return status;
+ }
+ else
+ {
+ /* It is more efficient not to encode */
+ hpack_int(0x00, 7, entry->value_len, buffer + offset, &len);
+ offset += len;
+
+ memcpy(buffer + offset, entry->value, entry->value_len);
+ offset += entry->value_len;
+ }
}
- /* And now free the item */
+ /* ### TODO: Store the item in the lr dynamic table if we are allowed
+ to do that. We currently 'forget' that step, so we only
+ use pre-cached values */
+
+ /* And now free the item */
hpack_free_entry(entry, alloc);
}
ctx->first = ctx->last = NULL;