Made grpc_byte_buffer_reader able to decompress msgs.

pull/1963/head
David Garcia Quintas 10 years ago
parent 8507e150ba
commit 25d02d5637
  1. 61
      include/grpc/byte_buffer.h
  2. 3
      include/grpc/byte_buffer_reader.h
  3. 29
      include/grpc/grpc.h
  4. 18
      src/core/surface/byte_buffer.c
  5. 59
      src/core/surface/byte_buffer_reader.c
  6. 3
      src/core/surface/call.c
  7. 75
      test/core/surface/byte_buffer_reader_test.c

@ -34,10 +34,17 @@
#ifndef GRPC_BYTE_BUFFER_H #ifndef GRPC_BYTE_BUFFER_H
#define GRPC_BYTE_BUFFER_H #define GRPC_BYTE_BUFFER_H
#include <grpc/grpc.h>
#include <grpc/support/slice_buffer.h> #include <grpc/support/slice_buffer.h>
typedef enum { GRPC_BB_SLICE_BUFFER } grpc_byte_buffer_type; typedef enum {
GRPC_BB_SLICE_BUFFER,
/* Keep the GRPC_BB_COMPRESSED_* entries in the same order as the
* grpc_compression_algorithm enum entries. */
GRPC_BB_COMPRESSED_NONE, /* for overriding otherwise compressed channels */
GRPC_BB_COMPRESSED_DEFLATE,
GRPC_BB_COMPRESSED_GZIP
} grpc_byte_buffer_type;
/* byte buffers are containers for messages passed in from the public api's */ /* byte buffers are containers for messages passed in from the public api's */
struct grpc_byte_buffer { struct grpc_byte_buffer {
@ -46,5 +53,55 @@ struct grpc_byte_buffer {
gpr_slice_buffer slice_buffer; gpr_slice_buffer slice_buffer;
} data; } data;
}; };
typedef struct grpc_byte_buffer grpc_byte_buffer;
/** Returns the grpc_compression_algorithm enum value for a
* grpc_byte_buffer_type GRPC_BB_COMPRESSED_* value. */
#define GRPC_COMPRESS_ALGORITHM_FROM_BB_TYPE(bb_type) \
(bb_type - GRPC_BB_COMPRESSED_NONE)
/** Returns a byte buffer instance over the given slices (up to \a nslices) of
* \a type type.
*
* Increases the reference count for all \a slices processed.
*
* The user is responsible for invoking grpc_byte_buffer_destroy on
* the returned instance. */
grpc_byte_buffer *grpc_byte_buffer_typed_create(gpr_slice *slices,
size_t nslices,
grpc_byte_buffer_type type);
/** Convenience method for creating GRPC_BB_SLICE_BUFFER byte buffers. \sa
* grpc_byte_buffer_typed_create */
grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices);
/** Copies input byte buffer \a bb.
*
* Increases the reference count of all the source slices. The user is
* responsible for calling grpc_byte_buffer_destroy over the returned copy. */
grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb);
/** Returns the size of the given byte buffer, in bytes. */
size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
/** Destroys \a byte_buffer deallocating all its memory. */
void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
/** Reader for byte buffers. Iterates over slices in the byte buffer */
struct grpc_byte_buffer_reader;
typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
/** Initialize \a reader to read over \a buffer */
void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_byte_buffer *buffer);
/** Cleanup and destroy \a reader */
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
/** Updates \a slice with the next piece of data from from \a reader and returns
* 1. Returns 0 at the end of the stream. Caller is responsible for calling
* gpr_slice_unref on the result. */
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
gpr_slice *slice);
#endif /* GRPC_BYTE_BUFFER_H */ #endif /* GRPC_BYTE_BUFFER_H */

@ -38,7 +38,8 @@
#include <grpc/byte_buffer.h> #include <grpc/byte_buffer.h>
struct grpc_byte_buffer_reader { struct grpc_byte_buffer_reader {
grpc_byte_buffer *buffer; grpc_byte_buffer *buffer_in;
grpc_byte_buffer *buffer_out;
/* Different current objects correspond to different types of byte buffers */ /* Different current objects correspond to different types of byte buffers */
union { union {
/* Index into a slice buffer's array of slices */ /* Index into a slice buffer's array of slices */

@ -37,6 +37,7 @@
#include <grpc/status.h> #include <grpc/status.h>
#include <stddef.h> #include <stddef.h>
#include <grpc/byte_buffer.h>
#include <grpc/support/slice.h> #include <grpc/support/slice.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
@ -155,34 +156,6 @@ typedef enum grpc_call_error {
(start_write/add_metadata). Illegal on invoke/accept. */ (start_write/add_metadata). Illegal on invoke/accept. */
#define GRPC_WRITE_NO_COMPRESS (0x00000002u) #define GRPC_WRITE_NO_COMPRESS (0x00000002u)
/* A buffer of bytes */
struct grpc_byte_buffer;
typedef struct grpc_byte_buffer grpc_byte_buffer;
/* Sample helpers to obtain byte buffers (these will certainly move
someplace else) */
grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices);
grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb);
size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
/* Reader for byte buffers. Iterates over slices in the byte buffer */
struct grpc_byte_buffer_reader;
typedef struct grpc_byte_buffer_reader grpc_byte_buffer_reader;
/** Initialize \a reader to read over \a buffer */
void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_byte_buffer *buffer);
/** Cleanup and destroy \a reader */
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader);
/* At the end of the stream, returns 0. Otherwise, returns 1 and sets slice to
be the returned slice. Caller is responsible for calling gpr_slice_unref on
the result. */
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
gpr_slice *slice);
/* A single metadata element */ /* A single metadata element */
typedef struct grpc_metadata { typedef struct grpc_metadata {
const char *key; const char *key;

@ -36,10 +36,16 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices) { grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices) {
return grpc_byte_buffer_typed_create(slices, nslices, GRPC_BB_SLICE_BUFFER);
}
grpc_byte_buffer *grpc_byte_buffer_typed_create(gpr_slice *slices,
size_t nslices,
grpc_byte_buffer_type type) {
size_t i; size_t i;
grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer)); grpc_byte_buffer *bb = malloc(sizeof(grpc_byte_buffer));
bb->type = GRPC_BB_SLICE_BUFFER; bb->type = type;
gpr_slice_buffer_init(&bb->data.slice_buffer); gpr_slice_buffer_init(&bb->data.slice_buffer);
for (i = 0; i < nslices; i++) { for (i = 0; i < nslices; i++) {
gpr_slice_ref(slices[i]); gpr_slice_ref(slices[i]);
@ -49,9 +55,13 @@ grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices) {
return bb; return bb;
} }
grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) { grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) {
switch (bb->type) { switch (bb->type) {
case GRPC_BB_SLICE_BUFFER: case GRPC_BB_SLICE_BUFFER:
case GRPC_BB_COMPRESSED_NONE:
case GRPC_BB_COMPRESSED_DEFLATE:
case GRPC_BB_COMPRESSED_GZIP:
return grpc_byte_buffer_create(bb->data.slice_buffer.slices, return grpc_byte_buffer_create(bb->data.slice_buffer.slices,
bb->data.slice_buffer.count); bb->data.slice_buffer.count);
} }
@ -64,6 +74,9 @@ void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
if (!bb) return; if (!bb) return;
switch (bb->type) { switch (bb->type) {
case GRPC_BB_SLICE_BUFFER: case GRPC_BB_SLICE_BUFFER:
case GRPC_BB_COMPRESSED_NONE:
case GRPC_BB_COMPRESSED_DEFLATE:
case GRPC_BB_COMPRESSED_GZIP:
gpr_slice_buffer_destroy(&bb->data.slice_buffer); gpr_slice_buffer_destroy(&bb->data.slice_buffer);
break; break;
} }
@ -73,6 +86,9 @@ void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) { size_t grpc_byte_buffer_length(grpc_byte_buffer *bb) {
switch (bb->type) { switch (bb->type) {
case GRPC_BB_SLICE_BUFFER: case GRPC_BB_SLICE_BUFFER:
case GRPC_BB_COMPRESSED_NONE:
case GRPC_BB_COMPRESSED_DEFLATE:
case GRPC_BB_COMPRESSED_GZIP:
return bb->data.slice_buffer.length; return bb->data.slice_buffer.length;
} }
gpr_log(GPR_ERROR, "should never reach here"); gpr_log(GPR_ERROR, "should never reach here");

@ -39,35 +39,68 @@
#include <grpc/support/slice_buffer.h> #include <grpc/support/slice_buffer.h>
#include <grpc/byte_buffer.h> #include <grpc/byte_buffer.h>
#include "src/core/compression/algorithm.h"
#include "src/core/compression/message_compress.h"
void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader, void grpc_byte_buffer_reader_init(grpc_byte_buffer_reader *reader,
grpc_byte_buffer *buffer) { grpc_byte_buffer *buffer) {
reader->buffer = buffer; grpc_compression_algorithm compress_algo;
gpr_slice_buffer decompressed_slices_buffer;
reader->buffer_in = buffer;
switch (buffer->type) { switch (buffer->type) {
case GRPC_BB_COMPRESSED_DEFLATE:
case GRPC_BB_COMPRESSED_GZIP:
compress_algo =
GRPC_COMPRESS_ALGORITHM_FROM_BB_TYPE(reader->buffer_in->type);
gpr_slice_buffer_init(&decompressed_slices_buffer);
grpc_msg_decompress(compress_algo, &reader->buffer_in->data.slice_buffer,
&decompressed_slices_buffer);
/* the output buffer is a regular GRPC_BB_SLICE_BUFFER */
reader->buffer_out = grpc_byte_buffer_create(
decompressed_slices_buffer.slices,
decompressed_slices_buffer.count);
gpr_slice_buffer_destroy(&decompressed_slices_buffer);
/* fallthrough */
case GRPC_BB_SLICE_BUFFER: case GRPC_BB_SLICE_BUFFER:
case GRPC_BB_COMPRESSED_NONE:
reader->current.index = 0; reader->current.index = 0;
} }
} }
void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) { void grpc_byte_buffer_reader_destroy(grpc_byte_buffer_reader *reader) {
/* no-op: the user is responsible for memory deallocation. switch (reader->buffer_in->type) {
* Other cleanup operations would go here if needed. */ case GRPC_BB_COMPRESSED_DEFLATE:
case GRPC_BB_COMPRESSED_GZIP:
grpc_byte_buffer_destroy(reader->buffer_out);
break;
case GRPC_BB_SLICE_BUFFER:
case GRPC_BB_COMPRESSED_NONE:
; /* no-op */
}
} }
int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader, int grpc_byte_buffer_reader_next(grpc_byte_buffer_reader *reader,
gpr_slice *slice) { gpr_slice *slice) {
grpc_byte_buffer *buffer = reader->buffer;
gpr_slice_buffer *slice_buffer; gpr_slice_buffer *slice_buffer;
switch (buffer->type) { grpc_byte_buffer *buffer = NULL;
/* Pick the right buffer based on the input type */
switch (reader->buffer_in->type) {
case GRPC_BB_SLICE_BUFFER: case GRPC_BB_SLICE_BUFFER:
slice_buffer = &buffer->data.slice_buffer; case GRPC_BB_COMPRESSED_NONE:
if (reader->current.index < slice_buffer->count) { buffer = reader->buffer_in;
*slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]);
reader->current.index += 1;
return 1;
} else {
return 0;
}
break; break;
case GRPC_BB_COMPRESSED_DEFLATE:
case GRPC_BB_COMPRESSED_GZIP:
buffer = reader->buffer_out;
break;
}
GPR_ASSERT(buffer);
slice_buffer = &buffer->data.slice_buffer;
if (reader->current.index < slice_buffer->count) {
*slice = gpr_slice_ref(slice_buffer->slices[reader->current.index]);
reader->current.index += 1;
return 1;
} }
return 0; return 0;
} }

@ -806,6 +806,9 @@ static void copy_byte_buffer_to_stream_ops(grpc_byte_buffer *byte_buffer,
switch (byte_buffer->type) { switch (byte_buffer->type) {
case GRPC_BB_SLICE_BUFFER: case GRPC_BB_SLICE_BUFFER:
case GRPC_BB_COMPRESSED_NONE:
case GRPC_BB_COMPRESSED_DEFLATE:
case GRPC_BB_COMPRESSED_GZIP:
for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) { for (i = 0; i < byte_buffer->data.slice_buffer.count; i++) {
gpr_slice slice = byte_buffer->data.slice_buffer.slices[i]; gpr_slice slice = byte_buffer->data.slice_buffer.slices[i];
gpr_slice_ref(slice); gpr_slice_ref(slice);

@ -42,6 +42,8 @@
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include "test/core/util/test_config.h" #include "test/core/util/test_config.h"
#include "src/core/compression/message_compress.h"
#include <string.h> #include <string.h>
#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x) #define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
@ -89,9 +91,82 @@ static void test_read_one_slice_malloc(void) {
grpc_byte_buffer_destroy(buffer); grpc_byte_buffer_destroy(buffer);
} }
static void test_read_none_compressed_slice(void) {
gpr_slice slice;
grpc_byte_buffer *buffer;
grpc_byte_buffer_reader reader;
gpr_slice first_slice, second_slice;
int first_code, second_code;
LOG_TEST("test_read_none_compressed_slice");
slice = gpr_slice_from_copied_string("test");
buffer = grpc_byte_buffer_typed_create(&slice, 1, GRPC_BB_COMPRESSED_NONE);
gpr_slice_unref(slice);
grpc_byte_buffer_reader_init(&reader, buffer);
first_code = grpc_byte_buffer_reader_next(&reader, &first_slice);
GPR_ASSERT(first_code != 0);
GPR_ASSERT(memcmp(GPR_SLICE_START_PTR(first_slice), "test", 4) == 0);
gpr_slice_unref(first_slice);
second_code = grpc_byte_buffer_reader_next(&reader, &second_slice);
GPR_ASSERT(second_code == 0);
grpc_byte_buffer_destroy(buffer);
}
static void read_compressed_slice(grpc_compression_algorithm algorithm,
int input_size) {
gpr_slice input_slice;
gpr_slice_buffer sliceb_in;
gpr_slice_buffer sliceb_out;
grpc_byte_buffer *buffer;
grpc_byte_buffer_reader reader;
gpr_slice read_slice;
int read_count = 0;
gpr_slice_buffer_init(&sliceb_in);
gpr_slice_buffer_init(&sliceb_out);
input_slice = gpr_slice_malloc(input_size);
memset(GPR_SLICE_START_PTR(input_slice), 'a', input_size);
gpr_slice_buffer_add(&sliceb_in, input_slice); /* takes ownership */
GPR_ASSERT(grpc_msg_compress(algorithm, &sliceb_in, &sliceb_out));
buffer = grpc_byte_buffer_typed_create(sliceb_out.slices, sliceb_out.count,
GRPC_BB_COMPRESSED_NONE + algorithm);
grpc_byte_buffer_reader_init(&reader, buffer);
while (grpc_byte_buffer_reader_next(&reader, &read_slice)) {
GPR_ASSERT(memcmp(GPR_SLICE_START_PTR(read_slice),
GPR_SLICE_START_PTR(input_slice) + read_count,
GPR_SLICE_LENGTH(read_slice)) == 0);
read_count += GPR_SLICE_LENGTH(read_slice);
gpr_slice_unref(read_slice);
}
GPR_ASSERT(read_count == input_size);
grpc_byte_buffer_reader_destroy(&reader);
grpc_byte_buffer_destroy(buffer);
gpr_slice_buffer_destroy(&sliceb_out);
gpr_slice_buffer_destroy(&sliceb_in);
}
static void test_read_gzip_compressed_slice(void) {
const int INPUT_SIZE = 2048;
LOG_TEST("test_read_gzip_compressed_slice");
read_compressed_slice(GRPC_COMPRESS_GZIP, INPUT_SIZE);
}
static void test_read_deflate_compressed_slice(void) {
const int INPUT_SIZE = 2048;
LOG_TEST("test_read_deflate_compressed_slice");
read_compressed_slice(GRPC_COMPRESS_DEFLATE, INPUT_SIZE);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
test_read_one_slice(); test_read_one_slice();
test_read_one_slice_malloc(); test_read_one_slice_malloc();
test_read_none_compressed_slice();
test_read_gzip_compressed_slice();
test_read_deflate_compressed_slice();
return 0; return 0;
} }

Loading…
Cancel
Save