| // Copyright 2021 The Chromium Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "components/reporting/compression/compression_module.h" | |
| #include <optional> | |
| #include <string> | |
| #include <utility> | |
| #include "base/feature_list.h" | |
| #include "base/functional/bind.h" | |
| #include "base/functional/callback.h" | |
| #include "base/memory/ref_counted.h" | |
| #include "base/task/thread_pool.h" | |
| #include "components/reporting/proto/synced/record.pb.h" | |
| #include "components/reporting/resources/resource_manager.h" | |
| #include "third_party/snappy/src/snappy.h" | |
| namespace reporting { | |
| // static | |
| scoped_refptr<CompressionModule> CompressionModule::Create( | |
| uint64_t compression_threshold, | |
| CompressionInformation::CompressionAlgorithm compression_type) { | |
| return base::WrapRefCounted( | |
| new CompressionModule(compression_threshold, compression_type)); | |
| } | |
| void CompressionModule::CompressRecord( | |
| std::string record, | |
| scoped_refptr<ResourceManager> memory_resource, | |
| base::OnceCallback<void(std::string, std::optional<CompressionInformation>)> | |
| cb) const { | |
| // Compress if record is larger than the compression threshold and compression | |
| // enabled | |
| switch (compression_type_) { | |
| case CompressionInformation::COMPRESSION_NONE: { | |
| // Don't compress, simply return serialized record | |
| CompressionInformation compression_information; | |
| compression_information.set_compression_algorithm( | |
| CompressionInformation::COMPRESSION_NONE); | |
| std::move(cb).Run(std::move(record), std::move(compression_information)); | |
| break; | |
| } | |
| case CompressionInformation::COMPRESSION_SNAPPY: { | |
| if (record.length() < compression_threshold_) { | |
| // Record size is smaller than threshold, don't compress. | |
| CompressionInformation compression_information; | |
| compression_information.set_compression_algorithm( | |
| CompressionInformation::COMPRESSION_NONE); | |
| std::move(cb).Run(std::move(record), | |
| std::move(compression_information)); | |
| return; | |
| } | |
| // Before doing compression, we must make sure there is enough memory - we | |
| // are going to temporarily double the record. | |
| ScopedReservation scoped_reservation(record.size(), memory_resource); | |
| if (!scoped_reservation.reserved()) { | |
| CompressionInformation compression_information; | |
| compression_information.set_compression_algorithm( | |
| CompressionInformation::COMPRESSION_NONE); | |
| std::move(cb).Run(std::move(record), | |
| std::move(compression_information)); | |
| return; | |
| } | |
| // Perform compression. | |
| CompressionModule::CompressRecordSnappy(std::move(record), std::move(cb)); | |
| break; | |
| } | |
| } | |
| } | |
| CompressionModule::CompressionModule( | |
| uint64_t compression_threshold, | |
| CompressionInformation::CompressionAlgorithm compression_type) | |
| : compression_type_(compression_type), | |
| compression_threshold_(compression_threshold) {} | |
| CompressionModule::~CompressionModule() = default; | |
| void CompressionModule::CompressRecordSnappy( | |
| std::string record, | |
| base::OnceCallback<void(std::string, std::optional<CompressionInformation>)> | |
| cb) const { | |
| // Compression is enabled and crosses the threshold. | |
| std::string output; | |
| snappy::Compress(record.data(), record.size(), &output); | |
| if (output.size() >= record.size()) { | |
| // Compression increases size, discard it. | |
| CompressionInformation compression_information; | |
| compression_information.set_compression_algorithm( | |
| CompressionInformation::COMPRESSION_NONE); | |
| std::move(cb).Run(std::move(record), std::move(compression_information)); | |
| return; | |
| } | |
| // Compression us shorter, accept it. | |
| // Return compressed string. | |
| CompressionInformation compression_information; | |
| compression_information.set_compression_algorithm( | |
| CompressionInformation::COMPRESSION_SNAPPY); | |
| std::move(cb).Run(std::move(output), std::move(compression_information)); | |
| } | |
| } // namespace reporting |