Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Conversation

@phaylon
Copy link
Contributor

@phaylon phaylon commented May 31, 2018

This adds:

  • Zlib compression/decompression via Compress::Zlib.
  • Options for compressors and zlibCompressionLevel in constructor and URIs.
  • Tests in devel/t-dynamic/OP_COMPRESSION.t.
  • An environment variable PERL_MONGO_TEST_COMPRESSION=zlib to run the test suite with compression enabled.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.2%) to 78.824% when pulling 24c49ac on shadow-dot-cat:phaylon/OP_COMPRESSED into 880e42f on mongodb:master.

Copy link
Contributor

@xdg xdg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid work! Thanks! I don't think it will take much to address my comments.

=attr zlib_compression_level
An integer from C<-1> to C<9> specifying the compression level to use
when L</compression> is set to C<zlib>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note the default (and meaning) of -1.

( ref( $self->ssl ) eq 'HASH' ? ( SSL_options => $self->ssl ) : () ),
},
monitoring_callback => $self->monitoring_callback,
compression => $self->compressors,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this attribute should be called "compressors" for consistency.


my %write_opt;
my $command_name = do {
my $command = _to_tied_ixhash($self->{query});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little concerned that this might be an expensive conversion to do for each operation just to get the command name. Extracting the _id field in insertion is a similar problem (where you know the document is one of only a few allowed types) and you can see how we do that here: https://github.com/mongodb/mongo-perl-driver/blob/880e42f6935fcac785b8d839a94d867a4f605066/lib/MongoDB/Role/_InsertPreEncoder.pm#L42-L50

return $res;
}

sub is_compressible {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is way too expensive for every operation (sub call and grep over list). Please just create a file-scoped hash with the prohibited command keys and check like $write_opt{disable_compression} = $IS_NOT_COMPRESSIBLE{$command_name}


sub write {
my ( $self, $buf ) = @_;
my ( $self, $buf, %write_opt ) = @_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make the option into a hashref. In the driver we try to avoid passing slurpy args.

sub try_uncompress {
my ($msg) = @_;

my ($len, $request_id, $response_to, $op_code, $orig_op_code, undef, $comp_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should unpack the original msg length here and use it below rather than the computed length of the reconstituted message. If there's any corruption in the decompression, that could help detect the problem.


$msg = substr $msg, P_COMPRESSED_PREFIX_LENGTH;

for my $comp_name (keys %COMPRESSOR) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than looping (O(N)), just build a file-scoped decompressor array that you can index into:

my @DECOMPRESSORS = [ sub { shift }, undef, \&_decompress_zlib ];

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And if the compressor becomes a coderef attribute of server, then you don't need the %COMPRESSOR hash at all, only an array of decompressor coderefs.

if ($COMPRESSOR{$comp_name}[0] == $comp_id) {
my $decomp_msg = $COMPRESSOR{$comp_name}[2]->($msg);
my $done =
pack(P_HEADER, 0, $request_id, $response_to, $orig_op_code)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, instead of 0, pack the original length extracted from the compressed header.

default => sub { {} },
);

has compressor => (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed above, maybe this should become an optional coderef that encapsulates the zlib_compression_level. The closure generator could still live in _Protocol so all the compression stuff is in one place and the _build_compressor method just calls MongoDB::_Protocol::get_compressor($name, $opts) or something like that.


sub _build_compressor {
my ($self) = @_;
my ($comp) = @{ ($self->is_master || {})->{compression} || [] };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A subtlety here: I don't think the server is required to return compressors in the preference order sent by the client, only an intersection. The client could send "zlib, snappy" and the server could reply with "snappy, zlib". So server probably needs to get a "preferred_compressors" attribute and this should take the servers reply in preference order.

@phaylon
Copy link
Contributor Author

phaylon commented Jun 8, 2018

Fixed and rebased version available in PR #162.

@phaylon phaylon closed this Jun 8, 2018
@TBSliver TBSliver deleted the phaylon/OP_COMPRESSED branch June 13, 2019 14:53
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants