/*
 * Copyright 2016, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 *    * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.grpc.netty;

import io.grpc.Metadata;
import io.grpc.Metadata.AsciiMarshaller;
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.util.AsciiString;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Header encoding benchmark.
 */
@State(Scope.Benchmark)
public class HeadersBenchmark {
  @Param({"1", "5", "10", "20"})
  public int headerCount;

  private final AsciiMarshaller<String> keyMarshaller = new AsciiMarshaller<String>() {
    @Override
    public String toAsciiString(String value) {
      return value;
    }

    @Override
    public String parseAsciiString(String serialized) {
      return serialized;
    }
  };

  private Metadata metadata = new Metadata();
  private AsciiString scheme = new AsciiString("https");
  private AsciiString defaultPath = new AsciiString("/Service.MethodMethodMethod");
  private AsciiString authority = new AsciiString("authority.googleapis.bogus");
  private AsciiString userAgent = new AsciiString("grpc-java-netty");

  @Setup
  public void setUp() throws Exception {
    for (int i = 0; i < headerCount; i++) {
      metadata.put(Metadata.Key.of("key-" + i, keyMarshaller), UUID.randomUUID().toString());
    }
  }

  @Benchmark
  @BenchmarkMode(Mode.SampleTime)
  @OutputTimeUnit(TimeUnit.NANOSECONDS)
  public Http2Headers convertClientHeaders() {
    return Utils.convertClientHeaders(metadata, scheme, defaultPath, authority, userAgent);
  }

  @Benchmark
  @BenchmarkMode(Mode.SampleTime)
  @OutputTimeUnit(TimeUnit.NANOSECONDS)
  public Http2Headers convertServerHeaders() {
    return Utils.convertServerHeaders(metadata);
  }
}

@@ -1664,40 +1664,242 @@
 tty.
-handler.codec.http2.Http2Headers
+buffer.ByteBuf;%0Aimport io.netty.buffer.UnpooledByteBufAllocator;%0Aimport io.netty.handler.codec.http2.DefaultHttp2HeadersEncoder;%0Aimport io.netty.handler.codec.http2.Http2Headers;%0Aimport io.netty.handler.codec.http2.Http2HeadersEncoder
 ;%0Aim
@@ -2798,16 +2798,22 @@
 private 
+final 
 Metadata
@@ -2842,32 +2842,38 @@
 ta();%0A  private 
+final 
 AsciiString sche
@@ -2905,32 +2905,38 @@
 ps%22);%0A  private 
+final 
 AsciiString defa
@@ -2995,32 +2995,38 @@
 od%22);%0A  private 
+final 
 AsciiString auth
@@ -3090,16 +3090,22 @@
 private 
+final 
 AsciiStr
@@ -3155,16 +3155,190 @@
 netty%22);
+%0A  private final Http2HeadersEncoder headersEncoder = new DefaultHttp2HeadersEncoder();%0A  private final ByteBuf scratchBuffer = UnpooledByteBufAllocator.DEFAULT.buffer(4096);
 %0A%0A  @Set
@@ -3887,32 +3887,32 @@
 rverHeaders() %7B%0A
-
     return Utils
@@ -3947,11 +3947,499 @@
 ta);%0A  %7D
+%0A%0A  /**%0A   * This will encode the random metadata fields, and repeatedly lookup the default other headers.%0A   */%0A  @Benchmark%0A  @BenchmarkMode(Mode.SampleTime)%0A  @OutputTimeUnit(TimeUnit.NANOSECONDS)%0A  public ByteBuf encodeClientHeaders() throws Exception %7B%0A    scratchBuffer.clear();%0A    Http2Headers headers =%0A        Utils.convertClientHeaders(metadata, scheme, defaultPath, authority, userAgent);%0A    headersEncoder.encodeHeaders(headers, scratchBuffer);%0A    return scratchBuffer;%0A  %7D
 %0A%7D%0A

add a header encoding benchmark