core: add Metadata.discardAll()

Metadata.removeAll creates an iterator for looking through removed
values even if the call doens't use it.  This change adds a similar
method which doesn't create garbage.

This change makes it easier in the future to alter the internals
of Metadata where it may be expensive to return removed values.
This commit is contained in:
Carl Mastrangelo 2016-09-07 14:55:34 -07:00
parent 5379de726d
commit f78644d762
8 changed files with 33 additions and 12 deletions

View File

@ -271,6 +271,16 @@ public final class Metadata {
return new ValueIterable<T>(key, values); return new ValueIterable<T>(key, values);
} }
/**
* Remove all values for the given key without returning them. This is a minor performance
* optimization if you do not need the previous values.
*/
@ExperimentalApi
public <T> void discardAll(Key<T> key) {
List<MetadataEntry> removed = store.remove(key.name());
storeCount -= removed != null ? removed.size() : 0;
}
/** /**
* Serialize all the metadata entries. * Serialize all the metadata entries.
* *

View File

@ -145,8 +145,8 @@ public abstract class AbstractServerStream extends AbstractStream2
} }
private void addStatusToTrailers(Metadata trailers, Status status) { private void addStatusToTrailers(Metadata trailers, Status status) {
trailers.removeAll(Status.CODE_KEY); trailers.discardAll(Status.CODE_KEY);
trailers.removeAll(Status.MESSAGE_KEY); trailers.discardAll(Status.MESSAGE_KEY);
trailers.put(Status.CODE_KEY, status); trailers.put(Status.CODE_KEY, status);
if (status.getDescription() != null) { if (status.getDescription() != null) {
trailers.put(Status.MESSAGE_KEY, status.getDescription()); trailers.put(Status.MESSAGE_KEY, status.getDescription());

View File

@ -140,12 +140,12 @@ final class ClientCallImpl<ReqT, RespT> extends ClientCall<ReqT, RespT>
@VisibleForTesting @VisibleForTesting
static void prepareHeaders(Metadata headers, DecompressorRegistry decompressorRegistry, static void prepareHeaders(Metadata headers, DecompressorRegistry decompressorRegistry,
Compressor compressor) { Compressor compressor) {
headers.removeAll(MESSAGE_ENCODING_KEY); headers.discardAll(MESSAGE_ENCODING_KEY);
if (compressor != Codec.Identity.NONE) { if (compressor != Codec.Identity.NONE) {
headers.put(MESSAGE_ENCODING_KEY, compressor.getMessageEncoding()); headers.put(MESSAGE_ENCODING_KEY, compressor.getMessageEncoding());
} }
headers.removeAll(MESSAGE_ACCEPT_ENCODING_KEY); headers.discardAll(MESSAGE_ACCEPT_ENCODING_KEY);
String advertisedEncodings = decompressorRegistry.getRawAdvertisedMessageEncodings(); String advertisedEncodings = decompressorRegistry.getRawAdvertisedMessageEncodings();
if (!advertisedEncodings.isEmpty()) { if (!advertisedEncodings.isEmpty()) {
headers.put(MESSAGE_ACCEPT_ENCODING_KEY, advertisedEncodings); headers.put(MESSAGE_ACCEPT_ENCODING_KEY, advertisedEncodings);
@ -251,7 +251,7 @@ final class ClientCallImpl<ReqT, RespT> extends ClientCall<ReqT, RespT>
*/ */
private static void updateTimeoutHeaders(@Nullable Deadline effectiveDeadline, private static void updateTimeoutHeaders(@Nullable Deadline effectiveDeadline,
@Nullable Deadline callDeadline, @Nullable Deadline outerCallDeadline, Metadata headers) { @Nullable Deadline callDeadline, @Nullable Deadline outerCallDeadline, Metadata headers) {
headers.removeAll(TIMEOUT_KEY); headers.discardAll(TIMEOUT_KEY);
if (effectiveDeadline == null) { if (effectiveDeadline == null) {
return; return;

View File

@ -238,8 +238,8 @@ public abstract class Http2ClientStream extends AbstractClientStream<Integer> {
* the application layer. * the application layer.
*/ */
private static void stripTransportDetails(Metadata metadata) { private static void stripTransportDetails(Metadata metadata) {
metadata.removeAll(HTTP2_STATUS); metadata.discardAll(HTTP2_STATUS);
metadata.removeAll(Status.CODE_KEY); metadata.discardAll(Status.CODE_KEY);
metadata.removeAll(Status.MESSAGE_KEY); metadata.discardAll(Status.MESSAGE_KEY);
} }
} }

View File

@ -104,7 +104,7 @@ final class ServerCallImpl<ReqT, RespT> extends ServerCall<ReqT, RespT> {
checkState(!sendHeadersCalled, "sendHeaders has already been called"); checkState(!sendHeadersCalled, "sendHeaders has already been called");
checkState(!closeCalled, "call is closed"); checkState(!closeCalled, "call is closed");
headers.removeAll(MESSAGE_ENCODING_KEY); headers.discardAll(MESSAGE_ENCODING_KEY);
if (compressor == null) { if (compressor == null) {
compressor = Codec.Identity.NONE; compressor = Codec.Identity.NONE;
} else { } else {
@ -125,7 +125,7 @@ final class ServerCallImpl<ReqT, RespT> extends ServerCall<ReqT, RespT> {
stream.setCompressor(compressor); stream.setCompressor(compressor);
headers.removeAll(MESSAGE_ACCEPT_ENCODING_KEY); headers.discardAll(MESSAGE_ACCEPT_ENCODING_KEY);
String advertisedEncodings = decompressorRegistry.getRawAdvertisedMessageEncodings(); String advertisedEncodings = decompressorRegistry.getRawAdvertisedMessageEncodings();
if (!advertisedEncodings.isEmpty()) { if (!advertisedEncodings.isEmpty()) {
headers.put(MESSAGE_ACCEPT_ENCODING_KEY, advertisedEncodings); headers.put(MESSAGE_ACCEPT_ENCODING_KEY, advertisedEncodings);

View File

@ -114,6 +114,17 @@ public class MetadataTest {
assertEquals(null, metadata.get(KEY)); assertEquals(null, metadata.get(KEY));
} }
@Test
public void discardAll() {
Fish lance = new Fish(LANCE);
Metadata metadata = new Metadata();
metadata.put(KEY, lance);
metadata.discardAll(KEY);
assertEquals(null, metadata.getAll(KEY));
assertEquals(null, metadata.get(KEY));
}
@Test @Test
public void testGetAllNoRemove() { public void testGetAllNoRemove() {
Fish lance = new Fish(LANCE); Fish lance = new Fish(LANCE);

View File

@ -105,7 +105,7 @@ abstract class NettyClientStream extends Http2ClientStream implements StreamIdHo
defaultPath = new AsciiString("/" + method.getFullMethodName()); defaultPath = new AsciiString("/" + method.getFullMethodName());
methodDescriptorAccessor.setRawMethodName(method, defaultPath); methodDescriptorAccessor.setRawMethodName(method, defaultPath);
} }
headers.removeAll(GrpcUtil.USER_AGENT_KEY); headers.discardAll(GrpcUtil.USER_AGENT_KEY);
Http2Headers http2Headers Http2Headers http2Headers
= Utils.convertClientHeaders(headers, scheme, defaultPath, authority, userAgent); = Utils.convertClientHeaders(headers, scheme, defaultPath, authority, userAgent);
headers = null; headers = null;

View File

@ -139,7 +139,7 @@ class OkHttpClientStream extends Http2ClientStream {
public void start(ClientStreamListener listener) { public void start(ClientStreamListener listener) {
super.start(listener); super.start(listener);
String defaultPath = "/" + method.getFullMethodName(); String defaultPath = "/" + method.getFullMethodName();
headers.removeAll(GrpcUtil.USER_AGENT_KEY); headers.discardAll(GrpcUtil.USER_AGENT_KEY);
List<Header> requestHeaders = List<Header> requestHeaders =
Headers.createRequestHeaders(headers, defaultPath, authority, userAgent); Headers.createRequestHeaders(headers, defaultPath, authority, userAgent);
headers = null; headers = null;