1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SRC_TRACE_PROCESSOR_RPC_QUERY_RESULT_SERIALIZER_H_ 18 #define SRC_TRACE_PROCESSOR_RPC_QUERY_RESULT_SERIALIZER_H_ 19 20 #include <memory> 21 #include <vector> 22 23 #include <limits.h> 24 #include <stddef.h> 25 #include <stdint.h> 26 27 namespace perfetto { 28 29 namespace protos { 30 namespace pbzero { 31 class QueryResult; 32 } // namespace pbzero 33 } // namespace protos 34 35 namespace trace_processor { 36 37 class Iterator; 38 class IteratorImpl; 39 40 // This class serializes a TraceProcessor query result (i.e. an Iterator) 41 // into batches of QueryResult (trace_processor.proto). This class 42 // returns results in batches, allowing to deal with O(M) results without 43 // full memory buffering. It works as follows: 44 // - The iterator is passed in the constructor. 45 // - The client is expected to call Serialize(out_buf) until EOF is reached. 46 // - For each Serialize() call, this class will serialize a batch of cells, 47 // stopping when either when a number of cells (|cells_per_batch_|) is reached 48 // or when the batch size exceeds (batch_split_threshold_). 49 // A batch is guaranteed to contain a number of cells that is an integer 50 // multiple of the column count (i.e. a batch is not truncated in the middle 51 // of a row). 52 // The intended use case is streaaming these batches onto through a 53 // chunked-encoded HTTP response, or through a repetition of Wasm calls. 54 class QueryResultSerializer { 55 public: 56 explicit QueryResultSerializer(Iterator); 57 ~QueryResultSerializer(); 58 59 // No copy or move. 60 QueryResultSerializer(const QueryResultSerializer&) = delete; 61 QueryResultSerializer& operator=(const QueryResultSerializer&) = delete; 62 63 // Appends the data to the passed protozero message. It returns true if more 64 // chunks are available (i.e. it returns NOT(|eof_reached_||)). The caller is 65 // supposed to keep calling this function until it returns false. 66 bool Serialize(protos::pbzero::QueryResult*); 67 68 // Like the above but stitches everything together in a vector. Incurs in 69 // extra copies. 70 bool Serialize(std::vector<uint8_t>*); 71 set_batch_size_for_testing(uint32_t cells_per_batch,uint32_t thres)72 void set_batch_size_for_testing(uint32_t cells_per_batch, uint32_t thres) { 73 cells_per_batch_ = cells_per_batch; 74 batch_split_threshold_ = thres; 75 } 76 77 private: 78 void SerializeColumnNames(protos::pbzero::QueryResult*); 79 void SerializeBatch(protos::pbzero::QueryResult*); 80 void MaybeSerializeError(protos::pbzero::QueryResult*); 81 82 std::unique_ptr<IteratorImpl> iter_; 83 const uint32_t num_cols_; 84 bool did_write_column_names_ = false; 85 bool eof_reached_ = false; 86 uint32_t col_ = UINT32_MAX; 87 88 // These params specify the thresholds for splitting the results in batches, 89 // in terms of: (1) max cells (row x cols); (2) serialized batch size in 90 // bytes, whichever is reached first. Note also that the byte limit is not 91 // 100% accurate and can occasionally yield to batches slighly larger than 92 // the limit (it splits on the next row *after* the limit is hit). 93 // Overridable for testing only. 94 uint32_t cells_per_batch_ = 50000; 95 uint32_t batch_split_threshold_ = 1024 * 128; 96 }; 97 98 } // namespace trace_processor 99 } // namespace perfetto 100 101 #endif // SRC_TRACE_PROCESSOR_RPC_QUERY_RESULT_SERIALIZER_H_ 102